深浅拷贝简介、深拷贝的方法有哪些、项目中遇到的深拷贝

也许我们都了解javascript中的基础类型有哪些:原始数据类型(Undefined、Null、Boolean、Number、String、Symbol),引用类型:Object
先看下面的场景,通过=赋值只是浅拷贝,因为属性是引用类型,拷贝的是内存地址,导致 其中一个对象(oldObj)改变了这个地址,就会影响到另一个对象(newObj)。这种情况怎么解决呢,当然是深拷贝了。可以通过下面的图了解下深浅拷贝的区别。
console.log(oldObj == newObj);//true,说明指向了同一个地址

const oldObj = {
        a: 1,
        b: {
          c: '12',
          d: '34',
        },
        d: function () {
          console.log('555');
        },
      };
      var newObj = oldObj;
      newObj.a = '666';
      newObj.b = {
        c: 666,
        d: 666,
      };
      console.log(oldObj);
//结果:
//a: "666"
//b: {c: 666, d: 666}
//d: ƒ ()

在这里插入图片描述
深拷贝就是从堆内存中开辟一个新的区域存放新对象,对对象中的子对象进行递归拷贝,拷贝前后的两个对象互不影响
在这里插入图片描述
深拷贝的实现方式:

1,JSON.parse(JSON.stringify())

parse方法可以将JSON字符串反序列化成JS对象,stringify方法可以将JS对象序列化成JSON字符串,这两个方法结合起来就能产生一个便捷的深克隆。
这个方法虽然可以解决绝大部分是使用场景,但是却有很多局限

1.1 他无法实现对函数 、RegExp等特殊对象的克隆
1.2 会抛弃对象的constructor,所有的构造函数会指向Object
1.3 对象有循环引用,会报错

下面先试下该方法的优越性,查看结果,深拷贝生效,改变newObj,oldObj不跟着改变。
打印下面,输出false,可进一步证明新旧对象
console.log(oldObj == newObj);//false
在这里插入图片描述
在这里插入图片描述
针对不能处理函数和正则,看下面对函数处理例子

 <script>
      const oldObj = {
        a: 1,
        b: {
          c: '12',
          d: '34',
        },
        d: person,
      };
      //   var newObj = JSON.parse(JSON.stringify(oldObj));
      var newObj = oldObj;
      newObj.a = '666';
      newObj.b = {
        c: 666,
        d: 666,
      };
      function person() {
        var name = 'lj';
        return name;
      }
      console.log(newObj.d); 
    </script>

打印结果为:

ƒ person() {
        var name = 'lj';
        return name;
      }

但是换成json深拷贝,结果是
在这里插入图片描述
看正则处理的例子,新增一个属性e,再使用JSON.parse(JSON.stringify(),很可惜结果是

      e: new RegExp('ab+c', 'i'),
console.log(oldObj.e);      /ab+c/i
console.log(newObj.e);     /{} 
//空的,得到的正则就不再是正则(变为空对象)

2、函数库lodash的_.cloneDeep方法

该函数库也有提供_.cloneDeep用来做 Deep Copy,转自思否讲的很详细

var _ = require('lodash');
var obj1 = {
    a: 1,
    b: { f: { g: 1 } },
    c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);// false

3、手写深拷贝

这个单独章节写个文章分享吧

4、项目遇到的问题

如下,调用接口获取到后端数据,并赋值给 that.cityList

 that.cityList = res.data;

that.cityList在data数据结构如下

   cityList: {
        priceA: "",
        driverP: "",
        driverP "",
        dynamicPList: [{beginTime:8:00,endTime:10:00},{},{}]
      },

我后面是需要将该对象里的数组遍历渲染出表单的形式,因涉及公司,这里不贴图片,总之就是说我需要展示并可修改cityList.dynamicPList每一项的值(即双向绑定),使用的element里的组件timepicker展示,该组件要求绑定一个数组,表示起始和结束时间,即我要在赋值的cityList中新创建一个变量[ item.time = [item.beginTime, item.endTime];],这时候就遇到问题了,时间修改不了,但是怎么解决呢?这就用到深拷贝了。
在这里插入图片描述
因为我新创建的属性每个item.time的值需要在页面双向绑定,但因为他指向了res.data,而res.data的数据是后端的数据,res.data是数组,属于引用类型,你改变cityList.dynamicPList中的item.time时,他的值总是指向res.data,但是这个数据vue根本没有检测到,因此数据无法实时改变,页面上表现为时间无法更改,除非你通过
this.cityList = JSON.parse(JSON.stringify(this.cityList));
解除数组的引用,其指针不再指向res.data,因此数据可以改变了。这是用到了深拷贝的地方。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值