1、概念
ECMAScript中的变量有两种类型:基本类型值和引用类型值。基本类型值指的是那些保存在栈内存中的简单数据段,即这种值完全保存在内存中的一个位置,基本类型值有Number、String、Boolean、Null、Undefined、Symbol。引用类型值指的是那些保存在堆内存中的对象,意思是变量中保存的实际上只是一个指针,这个指针指向内存中的另一个位置,该位置保存对象,引用类型值有Object、Array、Function等。
深拷贝和浅拷贝只存在引用类型值中。
浅拷贝类似于将一个对象obj1赋值给一个变量obj2,赋值后obj1和obj2指向同一个内存地址,修改其中一个会影响另外一个(浅拷贝时对象只会被拷贝最外部的一层,至于更深层的对象,则依然是通过引用指向同一块堆内存.)。深拷贝则是在内存中的另外一个地址创建一个对象obj3,除了指针指向的内存位置不同,obj3与obj1完全相同,obj3独立于obj1,操作一个对象时不会对另一个对象造成影响。。
2、深拷贝探究
2-1、 Array
Array的slice()、concat()、Array.from()方法只能实现一维数组的深拷贝,对二维及以上数组就无法深拷贝了。
Eg: [1, 2, 3, 'a']可以实现深拷贝,[1, 2, 3, [4, 5]]无法实现深拷贝。
2-2、Objec
Object.assign()方法只能实现一维对象的深拷贝,对二维及以上对象无法进行深拷贝。
Eg: {x: 1, y: 1}能实现深拷贝, {x: 1, y: {m: 2}}无法实现深拷贝。
2-3:、JSON.parse(JSON.stringify(obj)):
能实现一些比较简单的深拷贝,但是缺陷比较明显:当Object或Array中有值为undefined、所有函数及Symbol时,JSON.stringify(obj)将Object序列化时会忽略这些值,JSON.stringify(obj)将Array序列化时会将这些值转换为null。但是该方法足以应对比较简单的不含有上述值的对象。
2-4:JavaScript自身提供的方法不足以解决深拷贝的问题,所以需要借助其他方法。其一是递归函数,其二是使用第三方库,如jQuery的$.extend和lodash的_.deepCopy方法。
2-5、递归方法:
function deepCopy(obj) { // 创建一个新对象 let result = {} let keys = Object.keys(obj), key = null, temp = null; for (let i = 0; i < keys.length; i++) { key = keys[i]; temp = obj[key]; // 如果字段的值也是一个对象则递归操作 if (temp && typeof temp === 'object') { result[key] = deepCopy(temp); } else { // 否则直接赋值给新对象 result[key] = temp; } } return result; } var obj1 = { x: { m: 1 }, y: undefined, z: function add(z1, z2) { return z1 + z2 }, a: Symbol("foo") }; var obj2 = deepCopy(obj1); obj2.x.m = 2; console.log(obj1); //{x: {m: 1}, y: undefined, z: ƒ, a: Symbol(foo)} console.log(obj2); //{x: {m: 2}, y: undefined, z: ƒ, a: Symbol(foo)}
// 代码出自掘金的一篇博文,链接:https://juejin.im/post/5ad5b908f265da23870f540d