详细理解深浅拷贝存在的意义!!!

727 阅读3分钟

这是我参与8月更文挑战的第16天,活动详情查看:8月更文挑战

一、天降异象

说到深浅拷贝前,先来看两个现象,关于基本类型引用类型=号运算,看看有什么奇怪的事情发生

  • 基本类型进行=号运算时,现象和我们常理是相同的,不存在异样

    let a = 1;
    let b = a;
    b = 2;                          // a: 1  b: 2
    
  • 引用类型进行=号运算就出现问题了,贴代码

      let c = { name: "shengjingyin" };
      let d = c;
      d.name = "juliya";                // c:  {name: "juliya"} d:  {name: "juliya"}
    

    ??一万个??

    这是什么情况,我明明只是重新定义了d.name对吧?为什么c也跟着一起改变了?

原来啊,这和引用类型的存储方式有关,再来重温一下这张引用类型的数据存储方式。 image-20210816201339057.png

看到没有!引用类型的值是对象,保存在堆内存中,而栈内存存储的是对象的变量标识符以及对象在堆内存中的存储地址d经过赋值后,其实是和c的引用地址一样,他们开启堆中实体的"钥匙"是一模一样的,对象本质上是同一个。所以当我改变d.name时,c.name也受到影响

image-20210816201633224.png

二、深拷贝 & 浅拷贝

深浅拷贝的出现,就是为了解决这一问题,那么为何有两种拷贝呢?它们也是有着细微差别

先来看一个浅拷贝的一个实例,和上面的例子一样(这里先不要在意深浅拷贝是什么,后面会有总结)

let c = { name: "shengjingyin" };
let d = Object.assign({}, c);       // ES6方法
d.name = "juliya";                  // c:  {name: "shengjingyin"}   d:  {name: "juliya"}

这下完美解决了,cd的关联完全被断开了,可以开开心心的继续开发了,可是.....再来看一个代码

let c = { name: "shengjingyin", habit: ["篮球", "游泳"] };
let d = Object.assign({}, c);
d.habit.push("code");

可以看到!!!爱好这一栏又出现关联了!!!还让不让人写代码了!

image-20210816202642485.png 那么....接下来就是深拷贝的闪亮出场时刻了

let c = { name: "shengjingyin", habit: ["篮球", "游泳"] };
let d = JSON.parse(JSON.stringify(c));          //ES5           
d.habit.push("code");

这下又断开关联了!舒服

image-20210816203032204.png 通过上面的几个列子,知道深浅拷贝的作用了嘛?其实就是引用类型进行=号运算时,会产生一些奇怪的关联现象,这时我们需要特殊处理下,剪断它们两者之间的关联,这就是深浅拷贝的意义所在!!!(tips:对于基本类型的数据不需要深浅拷贝噢)

概念总结

  • 浅拷贝:可以理解为进行简单的拷贝,对于 对象(Object) 第一层的元素的属性值是基本类型的就相当于是基本类型的=号运算,完全复制;对于第一层的元素的属性值是引用类型的相当于还是引用类型的=号运算,这样子复制的还是引用类型的内存地址,而不是实体,所以还是会出现前后关联的问题;
  • 深拷贝:对于深拷贝,那就是可以理解为不管第几层,两者的关联都被剪断了,这前后两个变量没有任何关联,互不影响,相互独立。

总的来说,两者主要的区别是:对于第一层的属性为引用类型数据进行复制的时候,复制的是数据的引用还是实例,是引用则为浅拷贝,反之深拷贝