美文网首页
关于深浅拷贝的那些事

关于深浅拷贝的那些事

作者: 阿羡吖 | 来源:发表于2020-08-08 15:50 被阅读0次

    前言

    所谓深浅拷贝,其实都是进行复制,主要区别在于复制出来的新对象和原来的对象时候会相互影响。
    深浅拷贝的区分:B 复制 A,如何A 发生变化 B跟着变化 浅拷贝
    反之, 如果 B 不发生变化 则为深拷贝。
    浅拷贝 A B 指向同一个地址 所以 A受影响 B也会受影响

    深浅拷贝实例

      var a =[1,2,3,4]
      var a_clone = a;
      console.log(a === a_clone);
      a_clone[0] = 5;
      console.log(a_clone);
      console.log(a);
    
    image.png
      var obj=[1,2,3,[4,5]];
      var obj_extend =$.extend(true,{},obj);
      console.log(obj_extend === obj);
      console.log(obj_extend);
      console.log(obj);
    
    image.png

    要深入了解深浅拷贝必选先要了解其原理,这就不得不说到ECMAScript中的数据类型。

    基本类型和引用类型

    1、分类
    基本类型:undefined,null,布尔值(Boolean),字符串(String),数值(Number)
    引用类型:统称为Object类型,细分为:Function、Date、Array、Object类型等。
    2、不同的数据存储形式
    简单来说, 基本数据类型保存在栈内存 引用类型保存在堆内存
    2.1.1 栈内存
    栈内存中分别存储着变量的标识符以及变量的值

    image.png
    即:var a = "A"
    在栈内存中是这样的
    image.png
    2.1.2 堆内存
    栈内存存储的是变量的标识符以及对象在堆内存中的存储地址,但需要访问引用类型(对象、数组等)的值时,首先需要从栈中获得该对象的地址指针,然后再从对应的堆内存中取得所需的数据。
    image.png
    即:var a = {name:“jack”};
    在内存中是这样的: image.png

    3、不同类型的复制形式:
    基本类型的复制:当你在复制时,相当于把值也一并复制给了新的变量

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

    改变a的值,并不会影响到b。

    var a =1
    
    image.png
    var b = a;
    
    image.png
    a = 2;
    
    image.png

    引入类型:当复制引用类型时,实际上只是赋值起指向的内存地址,即原来的变量与复制的新变量指向了同一个东西

    var a ={name:"jack",age:20};
    var b = a;
    console.log(a === b);
    a.age =30;
    console.log(a);
    console.log(b)
    
    image.png

    可以看得出来:改变a的值,也会影响b的值
    内存中是这样的

    var a = {name:"jack",age:20}
    
    image.png
    var b = a;
    
    image.png
    a.age = 30;
    
    image.png

    看完上面之后,是不是就明白了。所谓深浅拷贝:
    对于仅仅是复制了引用(地址),换言之,原来的变量和新的变量指向了同一个东西,彼此之间的操作会互相影响,为浅拷贝
    反言之。如果是在堆中重新分配内存,拥有不同的地址,但是值是一样的,复制后的对象与原来的对象是完全隔离,互不影响的,为 深拷贝

    深浅拷贝的主要区别:复制的是引用(地址)还是复制的是实例。

    接下来就对上述实例进行深拷贝的实现

    实现深拷贝方式

    3.1、利用递归方式 对属性中所有的引用类型的值,遍历到是基本类型的值为止。
    function deepCLone(obj){
        var targetObj = Array.isArray(obj)?[]:{};
        for(var keys in obj){
            if(obj.hasOwnProperty(keys)){
                if(obj[keys] && typeof obj[keys] === 'object'){
                    targetObj[keys] = deepCLone(obj[keys])
                }else{
                    targetObj[keys] = obj[keys]
                }
            }
        }
        return targetObj
    }
    
    var a ={name:"jack",age:20};
    var b = deepCLone(a);
    console.log(b ===a);
    a.age = 30;
    console.log(a);
    console.log(b);
    
    image.png
    3.2、jQuery中的 extend复制方法

    可以用来扩展对象,这个方法可以传入一个参数:deep(true or
    false),表示是否执行深复制(如果执行深复制则会执行递归复制)

    深拷贝

    var obj = {name:"xixi",age:20,company:{name:"腾讯",address:"深圳"}};
    var obj_extend =$.extend(true,{},obj);
    console.log(obj === obj_extend);
    obj.company.name="阿里";
    obj.name="albabba";
    console.log(obj);
    console.log(obj_extend);
    
    image.png

    浅拷贝

    var obj = {name:"xixi",age:20,company:{name:"腾讯",address:"深圳"}};
    var obj_extend =$.extend(false,{},obj);
    console.log(obj === obj_extend);
    obj.company.name="阿里";
    obj.name="albabba";
    console.log(obj);
    console.log(obj_extend);
    
    image.png

    从company的变化可以看出,貌似是浅拷贝,但是name又貌似是深拷贝,这是何解。

    其实,Array的slice 和concat方法和jQuery中的extend复制方法,都是会复制第一层的值,对于第一层的值都是深拷贝,而到第二层的时候 Array的slice和concat方法就是复制引用,jQuery中的extend复制方法则取决于你的第一个参数,也就是时候进行递归复制。
    所谓第一层 就是 key所对应的value值是基本数据类型,也就是像实例中的name,age,而对于value值是引用类型 则为第二层,也就是像上面的company。

    顺便 我们可以试一下 slice 和concat

    var a =[1,2,3];
    var  b = a.slice();
    console.log(b === a);
    a[0] = 4;
    console.log(a);
    console.log(b);
    
    image.png

    concat

    var a =[1,2,3];
    var  b = a.concat();
    console.log(b === a);
    a[0] = 4;
    console.log(a);
    console.log(b);
    
    image.png

    看似是深拷贝,其实不然,下面的例子就说明了一切

    var a =[[1,2,3],4,5];
    var b= a.slice();
    a[0][0] = 6;
    console.log(a);
    console.log(b);
    
    image.png

    这就很明显的看出来了,上面所述,第一层是深拷贝 第二层 是引用。

    3.3、JSON对象的parse和stringify

    JSON对象中的stringify可以把一个js对象序列化为一个JSON字符串,parse可以把JSON字符串反序化为一个js对象,这两个方法实现的是深拷贝

    var obj ={name:'xixi',age:20,company:{name:'TX',address:'深圳'}};
    var obj_json = JSON.parse(JSON.stringify(obj));
    console.log(obj === obj_json);
    obj.name="ali";
    obj.company.name="AL";
    console.log(obj);
    console.log(obj_json);
    
    image.png

    妥妥的的深拷贝。

    原文地址,膜拜大佬:https://zhuanlan.zhihu.com/p/26282765

    相关文章

      网友评论

          本文标题:关于深浅拷贝的那些事

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