Javascript deep copy and shallow copy

js中深复制和浅复制

今天忽然想到了这个问题,总结一下js中有哪些复制对象的方法。先得明白什么是深复制,什么是浅复制,举个栗子:

var arr = [[1,2],3,4];
var brr = arr.slice();

//这时候brr是arr的浅复制
console.log(brr);

为啥呢?再试试这样:

brr[0][1] = 5;
console.log(arr)  // result is [[1,5],3,4];

因为arr[0]是一个数组,而brr[0]只是引用了这个数组;
所以深复制也就很好理解了,当改变任何brr的值都不会影响arr,那么该怎么实现呢?实现的方法有好几种,下面一一列举。

1.最熟悉的方法可能就是jQuery中的方法 $.extend(),看看jQuery官方的例子:

//浅复制
var object1 = {
  apple: 0,
  banana: { weight: 52, price: 100 },
  cherry: 97
};
var object2 = {
  banana: { price: 200 },
  durian: 100
};

// Merge object2 into object1
$.extend( object1, object2 );
//result is {"apple":0,"banana":{"price":200},"cherry":97,"durian":100}


//深复制
$.extend( true, object1, object2 );
//result is {"apple":0,"banana":{"weight":52,"price":200},"cherry":97,"durian":100}

深复制会递归的复制


2.原生的js实现

function clone(obj){
    //这一行很重要,判断obj是否基本类型 null,undefined,string,number,boolean,如果是直接返回,因为没法再继续循环了。
    if(obj == null || typeof obj !=='object') return obj

    if(obj instanceof Array){
        var arr = [];

        for(var i=0, len=obj.length; i<len; i++){
            //这一步就是深度复制的magic所在了
            arr[i] = clone(obj[i]);
        }

        return arr;
    }

    if(obj instanceof Object){
        //实例化obj的构造函数,得到和obj一样的prototype.
        var tem_obj = obj.constructor(); 

        for(attr in obj){
            if(obj.hasOwnProperty(attr)){
                //把obj实例的自有属性复制到temobj
                tem_obj[attr] = clone(obj[attr]);
            }
        }

        return tem_obj
    }
}

var arr = [[1,2],3,4];
var brr = clone(arr);
brr[0][1] = 5;
console.log(arr)  //[[1,2],3,4]

that’s it.


3.es6中的Object.assign,实行的是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。
详细的参考这里

Object.assign(target, source1, source2);

var obj1 = {a: {b: 1}};
var obj2 = Object.assign({}, obj1);

obj1.a.b = 2;
obj2.a.b // 2