js的深拷贝和浅拷贝

在实际工作中遇到需要拷贝数据的情况,可能是我们不能修改原始数据,必须拷贝一份修改
通常来说,我们拷贝数据可能是直接使用 = 赋值的形式。如果是基本数据类型= 赋值就会复制一份数据,互相不会影响
但是如果是对象类型的数据,= 赋值,仅仅是复制了对象的地址,两个变量通过地址找到的对象是同一个对象,这时候如果通过一个变量修改对象数据时,再通过另一个变量访问数据,你会发现,数据也发生改变了,因为两个变量指向的都是同一个对象。

      let a = {
        name: "xxj",
        age: 20,
      };
      let b = a;
      a.age = 22;
      console.log(b.age); //22

使用Object.assign()复制

      let a = {
        name: "xxj",
        age: 20,
      };
      let b = Object.assign({}, a);
      a.age = 22; //修改a.age
      console.log(b.age); //20, b.age不受影响

数据稍微复杂些:

      let a = {
        name: "xxj",
        age: 20,
        friend: {
          name: "张三",
          age: 50,
        },
      };
      let b = Object.assign({}, a);
      a.friend.name = "李四";
      console.log(b.friend); //{name: '李四', age: 50}

浅拷贝:只拷贝第一层原始类型值,和第一层的引用类型地址。
a.age属性值是一个原始类型,拷贝会复制一份,互不影响
a.friend属性值是一个引用类型,拷贝的是这个对象的地址,实际上a.friend 和 b.friend指向的是同一个对象obj(假设为obj),a.friend 和 b.friend保存的是obj的内存地址,我们通过该内存地址修改数据,再通过该内存地址找到这个数据,肯定是修改以后得数据了。

      console.log(a.friend === b.friend); //true

或者使用ES6的扩展运算符拷贝对象,也是一样的

      let a = {
        name: "xxj",
        age: 20,
        friend: {
          name: "张三",
          age: 50,
        },
      };
      let b = { ...a }; //ES6扩展运算符
      a.friend.name = "李四";
      console.log(b.friend); //{name: '李四', age: 50}
      console.log(a.friend === b.friend); //true

或者是数组的浅拷贝: Array.prototype.slice()

      let a = [
        1,
        "haha",
        {
          name: "张三",
          age: 22,
        },
      ];

      let b = a.slice();
      a[2].name = "李四";
      console.log(b[2]); //{name: '李四', age: 22}
      console.log(a[2] === b[2]); //true

这种拷贝达不到我们的要求:

深拷贝:拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象

这里只考虑手写的递归循环这个方法:

      // 递归实现深拷贝
      function deepCopy(target, map = new WeakMap()) {
        // 1. 是null,直接返回
        if (target === null) return target;
        // 2. 是基本类型,直接返回
        if (typeof target !== "object") return target;
        // 3. 是Date
        if (target instanceof Date) return new Date(target);
        // 4. 是正则
        if (target instanceof RegExp) return new RegExp(target);

        // 3. 是对象类型,要clone,创建克隆对象
        const cloneObj = new target.constructor();

        // 4. 解决循环引用
        if (map.get(target)) return map.get(target);
        else map.set(target, cloneObj);

        // map类型
        if (target instanceof Map) {
          for (const [key, value] of Object.entries(target)) {
            cloneObj.set(key, deepCopy(value, map));
          }
        }

        // set类型
        if (target instanceof Set) {
          for (const value of target) {
            cloneObj.add(deepCopy(value, map));
          }
        }

        for (const key in target) {
          if (target.hasOwnProperty(key)) {
            cloneObj[key] = deepCopy(target[([key], map)]);
          }
        }

        return cloneObj;
      }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值