美文网首页
JS中的深拷贝和浅拷贝

JS中的深拷贝和浅拷贝

作者: CoderZb | 来源:发表于2021-12-23 21:55 被阅读0次
    • 理解JS中的深拷贝和浅拷贝,必须知道如下两个知识点:

    JavaScript的数据类型

    值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)。
    引用数据类型:对象(Object)、数组(Array)、函数(Function)。

    JavaScript的数据类型的存储位置

    值类型(基本类型):内存地址在栈(stack)中。该类型在栈的内存中会分配固定的内存空间。
    引用数据类型:内存地址存在堆(Heap)中。该类型在堆的内存中动态分配内存空间。
    注意:引用数据类型会分配一个指针变量在栈上,通过这个指针变量来操作堆中的数据。
    在JS中操作的是栈上的指针变量,继而再找到堆中的内存地址。所以像如下=运算符赋值的操作,arrA和arrB的内容都为["1","5"]

    var arrA = ["1","2"]; 
    var arrB = arrA; 
    arrB[1] = "5";
    

    知道了如上两个知识点,我们来看看JS中的深拷贝和浅拷贝

    • 深拷贝是在栈中增加了一个指针变量的同时,在堆中对原有内存地址进行了拷贝,生成了一个新的内存地址,并且新增的指针变量保持着对新内存地址的引用,因此结果是堆中的两个不同的内存地址在栈中分别都有一个指针变量
    • 浅拷贝是在栈中增加了一个指针变量,该指针变量指向原来的堆中的内存地址,并没有增加新的内存地址,因此结果是栈中的两个指针变量指向的都是同一块内存地址
    • 在JS中,深拷贝和浅拷贝说的就是引用数据类型中的对象(Object)、数组(Array),和值类型(基本类型)没关系。
    • 在JS中,简单来说 深拷贝:数组B拷贝了数组A,数组B修改了,数组A不会修改;而浅拷贝:数组B拷贝了数组A,数组B修改了,数组A不会修改。

    js中的扩展运算符(...)、 concat 、 slice 是深拷贝还是浅拷贝?

    concatslice 以及 es6扩展运算符(...)仅仅是对第一层数据进行的是深拷贝,而对第二层、第三层....第N层进行的是浅拷贝。
    简而言之,使用concatslice 以及 es6扩展运算符(...)操作后的数据,数据中是基本类型的元素,该元素是深拷贝得到的;数据中是是引用数据类型的元素,该元素是深拷贝得到的。
    例如,["1","2",{id:"3"},["4","5"]]是被 es6扩展运算符(...)操作后的数据,那么元素"1""2"是深拷贝得到的,{id:"3"}["4","5"]是浅拷贝得到的,修改{id:"3"}["4","5"],原数据的{id:"3"}["4","5"]也会被修改。

    拿普通的=运算符concatslice 以及 es6扩展运算符(...)来举例:

    1.抛砖引玉:普通的=运算符对象(Object)、数组(Array)的拷贝为完全的浅拷贝

    无嵌套的普通数组:完全的浅拷贝(第一层到第N层)

    var arrA = ["1","2"];
    var arrB = arrA;
    arrB[1] = '5';
    console.log('arrA为--',arrA,'arrB为--',arrB);
    
    image.png
    数组Array嵌套了字典对象Object及数组Array:完全的浅拷贝(第一层到第N层)
    var arrA = ["1","2",{id:"3"},["4","5"]];
    var arrB = arrA;
    arrB[1] = '5';
    arrB[2].id = '6';
    arrB[3][1] = '7';
    console.log('arrA为--',arrA,'arrB为--',arrB);
    
    image.png
    字典对象Object嵌套了字典对象Object及数组Array:完全的浅拷贝(第一层到第N层)
    var dicA = {id1:"1",id2:"2",id3:{idx:"3"},id4:{idx:["4","5"],idy:["6","7"]}};
    var dicB = dicA;
    dicB.id2 = '8';
    dicB.id3.idx = '9';
    dicB.id4.idy[1] = '10';
    console.log('dicA为--',dicA,'dicB为--',dicB);
    
    image.png

    2.扩展运算符 ...

    无嵌套的普通数组:深拷贝

    var arrA = ["1","2"];
    var arrB = [...arrA];
    arrB[1] = '5';
    console.log('arrA为--',arrA,'arrB为--',arrB);
    
    image.png
    数组Array嵌套了字典对象Object及数组Array:第一层深拷贝,第二层到第N层浅拷贝
    var arrA = ["1","2",{id:"3"},["4","5"]];
    var arrB = [...arrA];
    arrB[1] = '5';
    arrB[2].id = '6';
    arrB[3][1] = '7';
    console.log('arrA为--',arrA,'arrB为--',arrB);
    
    image.png
    字典对象Object嵌套了字典对象Object及数组Array:第一层深拷贝,第二层到第N层浅拷贝
    var dicA = {id1:"1",id2:"2",id3:{idx:"3"},id4:{idx:["4","5"],idy:["6","7"]}};
    var dicB = {...dicA};
    dicB.id2 = '8';
    dicB.id3.idx = '9';
    dicB.id4.idy[1] = '10';
    console.log('dicA为--',dicA,'dicB为--',dicB);
    
    image.png

    3. concat 连接两个或多个数组

    无嵌套的普通数组:深拷贝

    var arrA = ["1","2"];
    var arrB = arrA.concat();
    arrB[1] = '5';
    console.log('arrA为--',arrA,'arrB为--',arrB);
    
    image.png
    数组Array嵌套了字典对象Object及数组Array:第一层深拷贝,第二层到第N层浅拷贝
    var arrA = ["1","2",{id:"3"},["4","5"]];
    var arrB = arrA.concat();
    arrB[1] = '5';
    arrB[2].id = '6';
    arrB[3][1] = '7';
    console.log('arrA为--',arrA,'arrB为--',arrB);
    
    image.png

    4.slice 数组截取

    无嵌套的普通数组:深拷贝

    var arrA = ["1","2"];
    var arrB = arrA.slice();
    arrB[1] = '5';
    console.log('arrA为--',arrA,'arrB为--',arrB);
    
    image.png
    数组Array嵌套了字典对象Object及数组Array:第一层深拷贝,第二层到第N层浅拷贝
    var arrA = ["1","2",{id:3},["4","5"]];
    var arrB = arrA.slice();
    arrB[1] = '5';
    arrB[2].id = '6';
    arrB[3][1] = '7';
    console.log('arrA为--',arrA,'arrB为--',arrB);
    
    image.png

    js中执行深拷贝的两种做法:

    • json对象转成json字符串JSON.stringify() ,json字符串转json对象JSON.parse()
    • 递归算法对每个层级都进行一次深拷贝

    相关文章

      网友评论

          本文标题:JS中的深拷贝和浅拷贝

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