在工作中遇到了深浅复制的问题,所以详细总结一下:
深复制和浅复制只针对像 Object, Array 这样的复杂对象的。简单来说,浅复制只复制一层对象的属性,而深复制则递归复制了所有层级。
var obj = { a:1, arr: [2,3] }; var shadowObj = shadowCopy(obj); function shadowCopy(src) { var dst = {}; for (var prop in src) { if (src.hasOwnProperty(prop)) { dst[prop] = src[prop]; } } return dst; }
这是一种典型的浅复制,shadowCopy方法将对象的各个属性进行依次复制,并不会进行递归复制,而 JavaScript 存储对象都是存地址的,所以浅复制会导致 obj.arr 和 shadowObj.arr 指向同一块内存地址。当其中一个变量对指向的值做了修改,另一个变量在调用时数值也就修改了。
shadowObj.arr[1] = 5; obj.arr[1] // = 5
下面给出深复制的代码:
function deepCopy ( obj ) { var tmp = {}; for ( var k in obj ) { tmp[ k ] = obj[ k ]; } return tmp; } //在这个函数中最关键的一步 tmp[ k ] = obj[ k ] //所以这里只需要保证 obj[ k ] 这个赋值是一个深度拷贝的对象即可. //注意: 函数的目的是得到 obj 的深拷贝副本. 因此递归一下. function deepCopy ( obj ) { var tmp = {}, k; for ( k in obj ) { if ( typeof obj[ k ] === 'object' ) { tmp[ k ] = deepCopy( obj[ k ] ); } else { tmp[ k ] = obj[ k ]; } } return tmp; } // 如果处理这个对象 var o3 = { name: 'jim', scores: [ 90, 95, 85 ] }; // 该代码无法处理数组的情况,做如下改动 function deepCopy ( obj ) { var tmp = obj.length >= 0 ? obj instanceof Array ? [] : { length: 0 } : {}, k; for ( k in obj ) { if ( typeof obj[ k ] === 'object' ) { tmp[ k ] = deepCopy( obj[ k ] ); } else { tmp[ k ] = obj[ k ]; } } return tmp; }
对于深复制,如果对象比较大,层级也比较多,深复制会带来性能上的问题。在遇到需要采用深复制的场景时,可以考虑有没有其他替代的方案。在实际的应用场景中,也是浅复制更为常用。
而JSON.parse( JSON.stringify(a) )这种方法比较简单,但同时也存在问题
- 无法复制函数
- 原型链没了,对象就是object,所属的类没了。这会抛弃对象的constructor,也就是深复制之后,无论这个对象原本的构造函数是什么,在深复制之后都会变成Object。另外诸如RegExp对象是无法通过这种方式深复制的。