深浅拷贝

101 阅读3分钟

引用类型才存在深浅拷贝的问题。基本数据类型之间是直接赋值。 浅拷贝:拷贝的是栈内存中的数据。如果是基本数据类型,就直接拷贝了基本变量里面的值。如果是引用类型,则只是拷贝了对象存在栈内存中的地址指针,所以此时指向堆内存中的同一个对象(即会出现一个对象发现变化后,另一个同步发生变化的问题)。

一、浅拷贝示例:

1、基本数据类型:

let x = 100 ;
let y = x;
console.log('x',x)
console.log('y',y)
x= 200
console.log('x',x)
console.log('y',y)

结果:

x 100
y 100
x 200
y 100

2、引用数据类型:

var a = {
    name:'小明',
    age:18
}
var b = a
console.log(a)
console.log(b)
console.log('a对象被修改后')
a.name='大明'
console.log(a)
console.log(b)

输出结果:

{ name: '小明', age: 18 }
{ name: '小明', age: 18 }
a对象被修改后
{ name: '大明', age: 18 }
{ name: '大明', age: 18 }

二、深拷贝: 浅拷贝因为指向同一个对象,产生了联动修改的效果。所以需要深拷贝,让两个变量指向两个对象。

一、如何实现深拷贝:

1、使用递归:

let people = {
    name: 'Tom',
    age: 18,
    happy:['吃饭','睡觉','打游戏','听歌'],
    lover:{
        name: 'Amy',
        age: 18,
        sex:'女'
    },
    do:function(name){
        console.log(this.name+'在打篮球')
    }
}

function cloneDeep(obj){
    // 如果不是引用类型,直接返回,不需要深拷贝
    if(typeof obj != 'object' || obj == null){
        return obj
    }
    let copyObj
    if(obj instanceof Array){
        copyObj = []
    }else 
        copyObj = {}

    for(i in obj){
        copyObj[i]=cloneDeep(obj[i])
    }
    return copyObj
}

let copyPeple = cloneDeep(people)
people.name='tom2号'
people.happy[0]='挨饿'
people.lover['age']=28//people.lover[age]='28':age is not defined
people.lover.name='Nene'
console.log('people',people)
people.do()
console.log('copyPeple',copyPeple)
copyPeple.do()

结果:原对象改变,新对象不受印象。

people {
  name: 'tom2号',
  age: 18,
  happy: [ '挨饿', '睡觉', '打游戏', '听歌' ],
  lover: { name: 'Nene', age: 28, sex: '女' },
  do: [Function: do]
}
tom2号在打篮球
copyPeple {
  name: 'Tom',
  age: 18,
  happy: [ '吃饭', '睡觉', '打游戏', '听歌' ],
  lover: { name: 'Amy', age: 18, sex: '女' },
  do: [Function: do]
}
Tom在打篮球

2、JSON.parse(JSON.stringify(被拷贝对象变量名)) 缺点: 缺点,无法实现对对象中方法的深拷贝


let people = {
    name: 'Tom',
    age: 18,
    happy:['吃饭','睡觉','打游戏','听歌'],
    lover:{
        name: 'Amy',
        age: 18,
        sex:'女'
    },
    do:function(name){
        console.log(this.name+'在打篮球')
    }
}
let copyPeople = JSON.parse(JSON.stringify(people))
people.name='tom2号'
people.happy[0]='挨饿'
people.lover['age']='28'//people.lover[age]='28':age is not defined
people.lover.name='Nene'
console.log(people)
console.log(copyPeople)
people.do()
copyPeople.do()//copyPeople.do is not a function  无法实现对对象中方法的深拷贝

结果

{
  name: 'tom2号',
  age: 18,
  happy: [ '挨饿', '睡觉', '打游戏', '听歌' ],
  lover: { name: 'Nene', age: '28', sex: '女' },
  do: [Function: do]
}
{
  name: 'Tom',
  age: 18,
  happy: [ '吃饭', '睡觉', '打游戏', '听歌' ],
  lover: { name: 'Amy', age: 18, sex: '女' }
}
tom2号在打篮球
TypeError: copyPeople.do is not a function

3、特殊:

3.1、Object.assign

Object.assign(对象a,对象b),把对象b的值,与对象a的值汇总,返回值为对象a。(范围是:所有可枚举属性的值)

 // 1、理解Object.assign()例子:
  const target = { a: 1, b: 2 };
  const source = { b: 4, c: 5 };
  const returnedTarget = Object.assign(target, source);
  console.log(target);// expected output: Object { a: 1, b: 4, c: 5 }
  console.log(returnedTarget);// expected output: Object { a: 1, b: 4, c: 5 }

Object.assign方法作用范围:

1、当对象只有一级属性为深拷贝;

2、当对象中有多级属性时,二级属性后就是浅拷贝

let a = {
    name:'kyp',
    age:18,
    happy:['吃饭','睡觉','打游戏','听歌'],
}
let b = Object.assign({},a)
a.name='kyp被修改了'
// a.happy='写代码'
a.happy[0]='写代码'
console.log(b)
console.log(a)

结果:

{ name: 'kyp', age: 18, happy: [ '写代码', '睡觉', '打游戏', '听歌' ] }
{ name: 'kyp被修改了', age: 18, happy: [ '写代码', '睡觉', '打游戏', '听歌' ] }

3.2、 数组api:concat与slice 个人觉得和Object.assign()挺像的,都是一级属性时就是深拷贝,二级属性及以上就是浅拷贝

let a = [1,2,{name:'kyp'}]
let b = [5,6]
// let b = ['a','b','c','d']
let c = a.concat(b)
a[0]='a'
// a[2]=[7,8]
a[2].name='修改了'
console.log(a);
console.log(c);

结果:

[ 'a', 2, { name: '修改了' } ]
[ 1, 2, { name: '修改了' }, 5, 6 ]