美文网首页
javascript的浅复制和深复制

javascript的浅复制和深复制

作者: id被吃 | 来源:发表于2017-10-12 22:51 被阅读9次

        javascript的基本类型包括字符串、数字、布尔、数组、对象、Null、Undefined。基本类型和对象最大的不同在于他们的传值方式:基本类型是按值传递的,但是对象是按引用传值的.
    基本类型:

    var a = 1;
    var b = a;
    b = 2;
    console.log(a);  //1
    console.log(b); //2
    

    从上面的例子可以看出,由于是按值传递,所以改变b的值不会改变a
    如果是对象,由于是按引用传值,类似的做法会改变另外一个相关对象的属性,这就是浅复制(新旧对象公用一块内存空间):

    var obj1 = { a:1 , b:2 };
    var obj2 = obj1;
    obj.a = 3;
    console.log(obj1);  //{ a:3 , b:2 }
    console.log(obj2);  //{ a:3 , b:2 }
    console.log(obj1 === obj2); //true
    

    如果不让原本obj1对象属性,那么就是深复制(新旧对象使用不同内存空间)
    简单实现:

    var obj2 = { a:obj1.a , b:obj1.b };
    obj2.a = 3;
    console.log(obj1);  //{ a:1 , b:2 }
    console.log(obj2);  //{ a:3 , b:2 }
    console.log(obj1 === obj2); //false
    

    这种方法可以实现深度复制,但是略显臃肿,而且如果有嵌套对象(有多层对象)实现起来就更麻烦了,比如:

    var obj1 = { grade : { math : 100 , Chinese : 90 } };
    var obj2 = { grade : obj1.grade };
    obj2.grade.math = 120;
    console.log(obj1);  // { grade : { math : 120 , Chinese : 90 } };  
    var obj2 = { grade : obj1.grade.math , grade : obj1.grade.Chinese }; //这样才能深度复制
    

    深度复制除了上面方法,还可以用其他方法实现

    1.ES6的Object.assign

    ES6引入了一个Object.assign的新函数,可以把任意个源对象自身的可枚举属性拷贝给目标对象,然后再返回目标对象。不过其进行的是浅复制i,复制的是对象属性的引用
    不过,它还是可以实现一层的深度复制,比起前面的手动复制要简单一点,比如

    var obj1 = { a:1 , b:2 };
    var obj2 = Object.assign( {} , obj1 };
    obj.a = 3;
    console.log(obj1);  //{ a:1 , b:2 }
    console.log(obj2);  //{ a:3 , b:2 }
    

    2.JSON.stringify+JSON.parse

    前面提到了,js的基本类型是按值传递的,那么既然有这样的特性我们完全可以将对象转换成字符串,然后再用parse解析成新对象

    var obj1 = { a:1 , b:2 };
    var obj2 = JSON.parse(JSON.stringify(obj1));
    obj.a = 3;
    console.log(obj1);  //{ a:1 , b:2 }
    console.log(obj2);  //{ a:3 , b:2 }
    console.log(obj1 === obj2); //false
    

    不过,这个方法还是有缺陷,只有可以转换成JSON格式的对象才可以使用,RegExp对象是无法通过该方法实现深度复制的,函数也无法使用

    3.递归拷贝

    function deepClone(initalObj,finalObj){
        var obj = finalObj || {};
        for(var i  in initalObj){
            var prop = initalObj[i];
            if(prop === obj)
              continue;
            if(typeof prop === 'object'){
                obj[i] = (prop.constructor === Array) ? [] : {};
                arguments.callee(prop,obj[i]);
            }else{
                obj[i] = prop;
            }
        }
        return obj;
    }
    

    4.Object.create(initalObj)

    注意和前面递归方法的区别

    function deepClone(initalObj,finalObj){
        var obj = finalObj || {};
        for(var i  in initalObj){
            var prop = initalObj[i];
            if(prop === obj)
              continue;
            if(typeof prop === 'object'){
                obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);
                arguments.callee(prop,obj[i]);
            }else{
                obj[i] = prop;
            }
        }
        return obj;
    }
    

    5.slice和concat巧妙的方法

    实质上这也是浅复制,只不过返回一个浅复制了原数组中的元素的一个新数组

    var arr1 = [1, 2, 3, 4],
        arr2 = arr1.slice(0),
        arr3 = arr1.concat();
     
    console.log(arr1, arr2, arr3);
    arr2[2] = 10;
    arr3[2] = 11;
    console.log(arr1[2], arr2[2], arr3[2]);
    > 1,2,3,4, 1,2,3,4, 1,2,3,4
    > 3, 10, 11
    
    console.log( arr1 === arr2 ); //false
    console.log( arr1 === arr3 ); //false
    

    又比如:

    var array = [1, [1,2,3], {name:"array"}]; 
    var array_concat = array.concat();
    var array_slice = array.slice(0);
    array_concat[1][0] = 5;  //改变array_concat中数组元素的值 
    console.log(array[1]); //[5,2,3] 
    console.log(array_slice[1]); //[5,2,3] 
    array_slice[2].name = "array_slice"; //改变array_slice中对象元素的值 
    console.log(array[2].name); //array_slice
    console.log(array_concat[2].name); //array_slice
    

    jQuery提供了一个$.extend方法可以做深度复制

    var arr1 = [1, 2, [3, 4], {a: 5, b: 6}, 7],
        arr2 = $.extend(true, [], arr1);
    console.log(arr1, arr2);
    arr2[1] = 10;
    console.log(arr1, arr2);
    

    还有一个叫lodash的函数库的_.cloneDeep方法可以实现深度复制

    参考:http://www.cnblogs.com/Chen-XiaoJun/p/6217373.html
    http://web.jobbole.com/88602/
    https://github.com/wengjq/Blog/issues/3

    相关文章

      网友评论

          本文标题:javascript的浅复制和深复制

          本文链接:https://www.haomeiwen.com/subject/nnxayxtx.html