JS 基础 (二)
浏览 715 | 评论 0
黄文勇
2020年05月11日

在讨论 深拷贝&浅拷贝之前,我们要先明白他们之间的定义和JS类型定义

深拷贝&浅拷贝的定义

深拷贝:深拷贝是指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响

浅拷贝:拷贝出来的目标对象的指针和源对象的指针指向的内存空间是同一块空间,浅拷贝只是一种简单的拷贝,让几个对象公用一个内存,然而当内存销毁的时候,指向这个内存空间的所有指针需要重新定义,不然会造成野指针错误。

JavaScript 的变量类型

Boolean、null、undefined、String、 Number 这5种基本类型的赋值是实际值;

Array,Function或Object赋值时是对象在内存中地址信息,不是实际值,所以我们改变对象中的值,被赋值对象输出的值也会相应发生改变

这就造成了我们在实际开发中经常会遇见 修改新数组却把旧数组同时修改的尴尬。

解决办法:深拷贝

1.我们怎么去实现深拷贝呢,这里可以递归递归去复制所有层级属性。

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;
//输出:[2,2,3,4],[1,2,3,4]

结果证明,数据完全独立与旧数组

前一篇文章中有个 slice方法也可以拷贝数据,但是它只能是浅拷贝,为什么这么说呢我们看数据

    let a = [1, 2, 3, 4],
        b = a.slice();
    a[0] = 2;
    console.log(a, b);
   //输出:[2,2,3,4],[1,2,3,4]

看到这里你可能会迷糊,这不就是相互独立的数据吗,怎么说是浅拷贝?
不急继续看,我们修改一下数据

    let a = [0, 1, [2, 3], 4],
        b = a.slice();
    a[0] = 1;
    a[2][0] = 1;
    console.log(a, b);
    //输出:[1,1,[1,3],4],[1,1,[1,3],4]

这里可以看出,拷贝的不彻底,深层属性还是共用了相同的地址,所以才造成上面的情况

同理,concat方法与slice也存在这样的情况,他们都不是真正的深拷贝,这里需要注意。

2.借用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;
    a[2][0] = 1;
    console.log(a, b);
    //输出:[1,1,[1,3],4],[0,1,[2,3],4]

这里讲解一下为什么 JSON.stringify(obj)&JSON.parse(obj) 就可以进行深拷贝:

原因:JSON.stringify(obj)可以将对象(数组)转为字符串,而字符串我们前面讲到字符串的赋值是实际值;这样就相当与实际值之间的赋值,互不影响。

而JSON.parse(obj)可以将字符串重新转化为对象(数组),这样就刚好完成了一个互不影响的深拷贝过程

JSON对象的parse和stringify在遇到function对象的时候就会立马报错,无法拷贝

3.借用JQ的extend方法,需要引入JQ

    let a = [0, 1, [2, 3], 4],
        b = $.extend(true, [], a);
    a[0] = 1;
    a[2][0] = 1;
    console.log(a, b);
    //输出:[1,1,[1,3],4],[0,1,[2,3],4]

参考文章

【JS】深拷贝与浅拷贝的区别,实现深拷贝的几种方法

本文作者:黄文勇
本文链接:https://www.3dcw.cn/index.php/archives/495/
最后修改时间:2020-11-09 10:38:25
本站未注明转载的文章均为原创,并采用 CC BY-NC-SA 4.0 授权协议,转载请注明来源,谢谢!
评论
与本文无关评论请发留言板。请不要水评论,谢谢。
textsms
支持 Markdown 语法
email
link
评论列表
暂无评论
arrow_back 上一篇
JS 基础 (一)
arrow_forward 下一篇
没有了