Object.assign()因为 Object.assign()拷贝的是属性值。假如源对象的属性值是一个对象的引用,那么它也只指向那个引用。如果合并的对象是多层嵌套对象那就属于浅拷贝了,修改内层对象的值还是会影响原对象。
要想实现深度复制可以使用JSON方式。
写法如下:
它的原理是把JS对象转换为JSON字符串,再由JSON字符串转换为JS对象,这样新对象的指针就不会指向原对象的指针了。但这种也有副作用的,有一下几点副作用:
1、有属性包含时间对象,拷贝后就是字符串的形式。
2、有函数或undefined,拷贝后会丢失。
3、有RegExp和Error对象,拷贝后变为空对象。
4、存在循环引用的情况,没法正确拷贝。
5、内层对象是构造函数生成的,会丢失constructor。
6、属性值为NaN、Infinity,拷贝后变为null。
虽然有些副作用,但大多情况还是符合要求可以使用。
简单来说,深拷贝主要是将另一个对象的属性值拷贝过来之后,另一个对象的属性值并不受到影响,因为此时它自己在堆中开辟了自己的内存区域,不受外界干扰。浅拷贝主要拷贝的是对象的引用值,当改变对象的值,另一个对象的值也会发生变化。
使用 js ON.stringify和 js ON.parse实现深拷贝:JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象;
缺陷:它会抛弃对象的 const ructor,深拷贝之后,不管这个对象原来的构造 函数 是什么,在深拷贝之后都会变成Object;这种方法能正确处理的对象只有 Number, String, Boolean, Array, 扁平对象,也就是说,只有可以转成JSON格式的对象才可以这样用,像function没办法转成JSON;
递归拷贝实现深拷贝,解决循环引用问题
我们先来复习下数据类型相关知识:此处引申知识点:基本数据类型
这里所说的赋值是对象的引用赋值,当我们把一个对象赋值给一个新的变量时,赋的其实是该对象在栈中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,因此,两个对象是联动的。
浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。即默认拷贝构造函数只是对对象进行浅拷贝复制(逐个成员依次拷贝),即只复制对象空间而不复制资源。
由此可见浅拷贝只解决了第一层的问题,如果接下去的值中还有对象,两者享有相同的地址。
深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。