JavaScrip对象复制--深度复制
JavaScript的对象复制存在一些容易犯错的位置,从下面代码可以看出来:
let obj = {
cat: 1,
a: { b: {c: 1} }
}
const sameObj = obj;
obj.a.b.c =2;
console.log(obj === sameObj); // ture
明明更改了初始的对象obj
,这两个对象还是相等。所以这赋值操作与一般的变量赋值是有区别的。js中这种直接赋值来复制对象是将原对象在内存中的引用(c语言中的指针)复制了过去,并没有给新的对象加入新的内存空间。当这两个对象中的一个对象改变时,于是这块内存也改变了,但是这两个对象都是指向这块内存空间,于是就发生了这种情况:当一个对象改变时,这两个对象都会改变。
所以要使用新的方法来复制对象:例如 Object.keys(),Object.assign(),for(let … in Obj)等方法来复制对象。
const obj2 = Object.assign({}, obj);
obj.cat = 2;
obj.a.b.c =2;
console.log(obj2.cat, obj.cat === obj2.cat); // 1, false
console.log(obj2.a.b.c, obj2.a.b.c === obj.a.b.c) // 2, true
第一条打印的结果是我们想要的,新对象与原始对象不再有联系。但是第二条打印结果却又出现来跟直接赋值来复制对象相识的情况:改变一个对象的属性值,另一个对象也相应的改变了。这是因为上述的复制方法也都是只把第一层属性值重新用赋值的方式复制了一下,如果第一层的属性值仍然是指向对象的引用,这些方法复制的依然是指针,所以改变其中一个对象第二层以上的属性值,还是会导致两个对象同时改变。
理解之后可以思考一下下面的打印结果
obj.a = 1;
console.log(obj2.a.b.c); // 2
使用const newObj = JSON.parse(JSON.stringify(obj))
可以实现复制对象是不再复制指针,进而两个对象不再有关联。可以这样理解:对象先转换成字符串,对象的指针信息自然就不再保存下来了,从这个字符串生成的对象也就没有了指针的关联,两个对象不再有任何关联。这种方法只有在原对象是json格式时有效,因为这种复制方法也会将原对象的方法(属性为函数)丢失。
ps:这样设计的目的是为了节省内存,所以为了这几kb的内存我就还是忍了吧!
递归函数深层复制