JS深拷贝与浅拷贝

杜夫

如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力。

function deepClone(obj){

let objClone = Array.isArray(obj)?[]:{};
if(obj && typeof obj==="object"){
    for(key in obj){
        if(obj.hasOwnProperty(key)){
            //判断ojb子元素是否为对象,如果是,递归复制
            if(obj[key]&&typeof obj[key] ==="object"){
                objClone[key] = deepClone(obj[key]);
            }else{
                //如果不是,简单复制
                objClone[key] = obj[key];
            }
        }
    }
}
return objClone;

}
let a=[1,2,3,4],

b=deepClone(a);

a[0]=2;
console.log(a,b);

这里再次强调,深拷贝,是拷贝对象各个层级的属性,可以看个例子。JQ里有一个extend方法也可以拷贝对象,我们来看看
let a=[1,2,3,4],

b=a.slice();

a[0]=2;
console.log(a,b);

那是不是说slice方法也是深拷贝了,毕竟b也没受a的影响,上面说了,深拷贝是会拷贝所有层级的属性,还是这个例子,我们把a改改
let a=[0,1,[2,3],4],

    b=a.slice();

a[0]=1;
a2=1;
console.log(a,b);

拷贝的不彻底啊,b对象的一级属性确实不受影响了,但是二级属性还是没能拷贝成功,仍然脱离不了a的控制,说明slice根本不是真正的深拷贝。
这里引用知乎问答里面的一张图

第一层的属性确实深拷贝,拥有了独立的内存,但更深的属性却仍然公用了地址,所以才会造成上面的问题。
同理,concat方法与slice也存在这样的情况,他们都不是真正的深拷贝,这里需要注意。

除了递归,我们还可以借用JSON对象的parse和stringify

function deepClone(obj){

let _obj = JSON.stringify(obj),
    objClone = JSON.parse(_obj);
return objClone

}
let a=[0,1,[2,3],4],

b=deepClone(a);

a[0]=1;
a2=1;
console.log(a,b);

可以看到,这下b是完全不受a的影响了。
附带说下,JSON.stringify与JSON.parse除了实现深拷贝,还能结合localStorage实现对象数组存储。有兴趣可以阅读博主这篇文章。
localStorage存储数组,对象,localStorage,sessionStorage存储数组对象

阅读 44

杜夫
生活很美好
29 声望
0 粉丝
0 条评论
你知道吗?

29 声望
0 粉丝
宣传栏