这里我们讨论一下JS的复杂引用类型的复制,不讨论简单数据类型的复制。 因为简单数据类型的值存在栈中,不存在引用值的情况。
对象的实例是存储在堆内存中,我们通过一个引用值去操作对象,所以在复制对象的时候就存在两种情况了:复制引用和复制实例。这就是深复制和浅复制的区别。
浅复制:复制引用,复制后的引用都指向同一个实例,如果其中一个引用的值改变了,另一个引用的值也会改变
深复制:深复制 不是简单的复制引用,而是在堆中重新分配内存,并把源对象实例的所有属性进行新建复制,复制之后的对象与源对象完全分离
对于深复制,如果源对象中有对象属性,就需要用到递归复制,保证复制对象和源对象完全分离。
浅复制的实现
1 2 3 4 5 6 7
| function(obj) { var copyObj = {}; for (var key in obj) { copyObj[key] = obj[key] } return copyObj; }
|
1 2 3 4 5 6 7
| var array = [1,2,3]; var array_shallow = array; var array_concat = array.concat(); var array_slice = array.slice(0); console.log(array === array_shallow); //true console.log(array === array_slice); //false console.log(array === array_concat); //false
|
他们虽返回了不同的数组实例,但是却不是真正的深复制,依然只是复制了引用,引用的对象改变了,源对象依然改变
json对象的parse和stringify
1 2 3 4 5 6 7 8 9
| var source = { name:"source", child:{ name:"child" } } var target = JSON.parse(JSON.stringify(source)); //改变target的name属性 target.name = "target"; console.log(source.name); //source console.log(target.name); //target //改变target的child target.child.name = "target child"; console.log(source.child.name); //child console.log(target.child.name); //target child
|
从代码可以看出,复制之后的对象与源对象完全分离,这个方法可以处理所有能用json格式表示的数据类型,但是对于正则表达式类型、函数类型等无法深度复制
,而且会直接丢失相应的值。如果对象中存在循环引用,也无法正确处理。
…