啥是浅拷贝啥是深拷贝呢?简单来说就是,比如变量a,把a拷贝给了b,如果b改变值不影响a就是深拷贝,b的改变引起a的改变就是浅拷贝
对于基本的数据类型number,string,boolean,null,undefined,可以把它们都当做是浅拷贝,因为深拷贝对复杂的数据类型才有意义,比如对象、数组、函数。
基本数据类型的浅拷贝:
从上面来看c变成111而a依然是100.
引用类型的浅拷贝:
把person1拷贝给了person2,当person2的name改成amy后,person1的name也变成了amy。为什么会变成这样呢?这就要说到栈和堆了。
基本类型的名字和值都存在栈,当b=a时会开辟出一块新的空间,所以当你改变b的时候,a是感知不到的。
引用类型就不一样了,当person2=person1的时候,栈开辟出一块地址存放person2变量,而在栈里面存放的是person1的地址值,不是person1的值,person1的值存放在堆中,这样子person1和person2共同指向同一个地址0x1111。当person2.name='amy’的时候,堆地址0x1111的值改变,而person1和person2都指向同一个地址值,所以person1的值也就跟着变化。
在开发中我们希望当person2的值改变不引起person1的改变,这时候就需要深拷贝了。
这里比较几种复杂数据类型的拷贝的方法,看看有什么异同以及使用的时候需要注意的地方。先看结果
let obj1 = {
id: 111,
name: 'zhangsan',
eat: function eat(){},
nums: [1, 2, 3],
address: {
city: 'shanghai'
}
}
红色表示不能深拷贝,绿色可以深拷贝
看代码
A
这是浅拷贝,最直接的拷贝方法,看结果:
从结果中我们看到,直接赋值后两者是相等的,地址值相等、值也相等,obj2改变后obj1的值也跟着改变。
B
使用Object.assign函数赋值,从结果我可以看出,obj2的基本类型id和name、函数eat、数组nums改变后并没有引起obj1相应的值改变,但是对象address的city却变了。所以,如果拷贝的对象中含有子对象,就不能使用Object.assign进行深拷贝
C
ES6中使用{…source}拷贝,结果和Object.assign是一样的,看结果
D
使用JSON.parse(JSON.stringify(obj1))。JSON.stringify会忽略掉函数,从结果图我们看到在change之前obj2的函数消失了,所以如果拷贝对象有函数慎用此方法。
E
lodash的cloneDeep是最完整的深度拷贝方法,不管是基本类型还是复杂类型都能深度拷贝。使用该方法需要引入lodash.
综上,在进行深度拷贝的时候要注意,选择合适的方法才不会出现莫名其妙的bug哦
路漫漫其修远兮,吾将上下而求索。
欢迎关注我的公众号“三横兰”