js对象的深浅拷贝

Posted 奔跑吧人生

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了js对象的深浅拷贝相关的知识,希望对你有一定的参考价值。

JS数据类型可以分为(ES5,暂时不考虑ES6):

  简单数据类型:Number、String、undefined、boolean

  复杂数据类型:Object、Array

简单的数据类型,往往是赋值操作,而复杂数据类型是引用操作。

赋值操作我们就不讲了,主要看看引用操作把

    var arr = [1,2,3];
    var arr2 = arr;
    arr2.push(4);
    console.log(arr);//输出[1,2,3,4]

明明是对arr2进行的操作,为什么arr也变化了呢?因为js存储对象都是存地址的,所以arr2实际存储的是:"arr在内存中的地址";

由此我们可以明白,既然都是指向同一个内存地址,当我们改变任何一个的时候,都会改变。

知道这个基本的特性那么我们可以试图来理解下浅复制和深复制

首先看一段代码,我们再来讲解下概念

 

技术分享图片
    var obj ={a:1,b:2,c:[1,2]};
    var shallowCopy = shallow(obj);
    function shallow(obj){
        var shallowObj = {};
        for(var name in obj){
            if(obj.hasOwnProperty(name)){
                shallowObj[name] = obj[name]
            }
        }
        return shallowObj
    }
    console.log(shallowCopy);//输出的就是这个对象,我们实现了简单的浅复制;
技术分享图片

浅复制:只会将对象的各个属性进行依次复制,并不会进行递归复制,而js存储对象都是存地址的,所以浅复制会导致obj.c和shallowCopy.c 指向同一块内存地址;会导致引用。

深复制:它不仅将原对象的各个属性逐个复制出去,而且将原对象各个属性所包含的对象也依次采用深复制的方法递归复制到新对象上。这就不会存在上面obj和shallowCopy的c属性指向同一个对象的问题。(待会贴出深复制的代码,这是个复杂的问题)

总结:需要注意的是,如果对象比较大,层级也比较多,深复制会带来性能上的问题。在遇到需要采用深复制的场景时,可以考虑有没有其他替代方案,在实际的引用场景中,也是浅复制更为常用。 

我现在给出一个简单版本的深复制,可以复制对象和数组(不考虑循环引用问题,函数对象问题),如果想深入研究的话可以看下这篇文章:http://jerryzou.com/posts/dive-into-deep-clone-in-javascript/

在这里我们只理解思想和简单的实现,实际项目中可以考虑使用lodash(http://lodashjs.com/docs/),或者jQuery的extend的方法也同样可以

技术分享图片
    function deepClone(obj){
        var newObj = obj.constructor === Array ? []:{};
        if(typeof obj !== ‘object‘){
            return
        }else{
            for(var i in obj){
                if(obj.hasOwnProperty(i)){
                    newObj[i] = typeof obj[i] === ‘object‘?deepClone(obj[i]):obj[i];
                }
            }
        }
        return newObj
    }
技术分享图片

最核心的思想还是采用递归的方式,不断进行,直到基本数据类型后,再复制

方法还有很多种,譬如还有使用JSON.stringify进行序列化,JSON.parse进行反序列化,实现"偷懒版"的深复制...等等

以上是关于js对象的深浅拷贝的主要内容,如果未能解决你的问题,请参考以下文章

js的深浅拷贝

JS深浅拷贝

js 深浅拷贝

最简js深浅拷贝说明

js通过一个方法实现对象的深浅拷贝。

从JS深浅拷贝谈原型设计模式