2021-04-02

深拷贝和浅拷贝的理解

1. 区分基本数据类型和引用类型

基本数据类型:直接存储在栈 (stack) 中的数据 包括:String, Number, Boolean, Null, Undefined,Symbol
引用类型:栈中存引用,真实的数据存储在堆中。包括:Object 、Array 、Function 、Data

2. 对比两个对象/数组是否相等
      let obj1 = {
        name: "lucy",
        age: 20,
      };
      let obj2 = {
        name: "lucy",
        age: 20,
      };
      console.log(obj1 === obj2); // false
      console.log(JSON.stringify(obj1) === JSON.stringify(obj2)); // true
      //-----------------------------------------------------------------
      let arr1 = ["nihao", "zaijian"];
      let arr2 = ["nihao", "zaijian"];
      console.log(arr1 === arr2); // false
      console.log(JSON.stringify(arr1) === JSON.stringify(arr2)); // true

原因在于对象和数组是引用类型,‘==’以及‘===’比较的是引用地址,两个对象虽然数据内容相同,但是引用地址不同,所以输出false, 转换为JSON字符串形式后,输出为true。

      let obj1 = {
        name: "lucy",
        age: 20,
      };
      let obj2 = obj1; //obj2和obj1指向同一个引用地址
      console.log(obj1 === obj2); // true
3. 深拷贝

首先引入一个问题,还是上面的代码

 let obj1 = {
        name: "lucy",
        age: 20,
      };
      let obj2 = obj1; //obj2和obj1指向同一个引用地址
      obj2.name = "peter";
      console.dir(obj1);
      console.dir(obj2);

输出结果:
在这里插入图片描述
原因很简单,引用两个对象指向同一个地址,所以他们‘共用’相同的数据,当某一方修改了数据,另一方自然会受到影响。
那如果我们的需求是一方改变了引用类型中的某一个属性,另一方不受到影响呢?这时候就需要引入深拷贝了。
深拷贝:在进行赋值之前,为引用类型的数据成员另辟了一个独立的内存空间,实现真正内容上的拷贝 。这种拷贝称为深拷贝。简单来说,就是重新开辟一个堆空间,专门存储另一个对象的数据,这样两个对象的数据就各自独立,不会互相影响。

3.1 深拷贝的方法1——JSON序列化

let obj1 = {
        name: "lucy",
        age: 20,
        hobby: {
          sport: "basketball",
        },
        beFriend() {},
      };
      function deepClone(obj1) {
      	//构造一个新的对象
        let obj2 = JSON.parse(JSON.stringify(obj1));
        obj2.name = "jensen";
        obj2.hobby.sport = "football";
        return obj2;
      }
      console.log(deepClone(obj1));
      console.log(obj1);

输出结果:
在这里插入图片描述
可以发现这样就实现了深拷贝,但是存在一个问题是原对象中的函数方法没有被拷贝。

3.2 深拷贝的方法2——遍历

遍历是更为常用的一种方法。
这里我们采用for in 方法进行遍历。

 let obj1 = {
        name: "lucy",
        age: 20,
        hobby: {
          sport: "basketball",
        },
        beFriend() {},
      };
      function deepClone(obj1) {
        // 如果typeof obj1.splice是function,那么obj1是数组类型, 否则是对象类型
        let result = typeof obj1.splice === "function" ? [] : {};
        if (typeof result == "object") {
          for (let el in obj1) {
            if (typeof obj1[el] == "object") {
              result[el] = deepClone(obj1[el]);
            } else {
              result[el] = obj1[el];
            }
          }
          return result;
        }
        return obj1;
      }
      function objClone(obj) {
        let obj2 = deepClone(obj1);
        obj2.name = "ezreal";
        obj2.hobby.sport = "run";
        return obj2;
      }
      console.log(objClone(obj1));
      console.log(obj1);

输出结果:
在这里插入图片描述

由此,我们利用for in 遍历 + 递归实现了一个较为完善的深拷贝。

3.3 深拷贝的方法3 — lodash库

引入一个lodash库,简单调用api即可。

    <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
    <script>
      let obj1 = {
        name: "lucy",
        age: 20,
        hobby: {
          sport: "basketball",
        },
        beFriend() {},
      };
      function dC(obj1) {
        let obj2 = _.cloneDeep(obj1);
        obj2.name = "sam";
        obj2.hobby.sport = "swim";
        return obj2;
      }
      console.log(dC(obj1));
      console.log(obj1);
    </script>

输出结果:
在这里插入图片描述

4. 浅拷贝

对比深拷贝即可, 浅拷贝就是只拷贝第一层引用。

4.1 浅拷贝方法1 —— 直接引用

      let arr1 = ["nihao", { name: "lucy" }];
      let arr2 = arr1;
      arr
      arr2[1].name = "faker";
      console.table(arr1);
      console.table(arr2);

输出结果:
在这里插入图片描述

4. 浅拷贝的方法2 —— 遍历

let arr1 = ["nihao", { name: "lucy" }];
      function shallowCopy(arr1) {
        let result = typeof arr1.splice === "function" ? [] : {};
        if (typeof arr1 === "object") {
          for (let el in arr1) {
            result[el] = arr1[el];
          }
          return result;
        }
        return arr1;
      }
      function arrCopy(arr1) {
        let arr2 = shallowCopy(arr1);
        arr2[0] = "zaijian";
        arr2[1].name = "dade";
        return arr2;
      }
      console.table(arrCopy(arr1));
      console.table(arr1);

输出结果:
在这里插入图片描述

4. 浅拷贝的方法3 —— Object.assign

      let arr1 = ["nihao", { name: "lucy" }];
      function arrCopy(arr1) {
        let arr2 = Object.assign(arr1, []);
        arr2[1].name = "ajax";
        return arr2;
      }
      console.table(arrCopy(arr1));
      console.table(arr1);

输出结果:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值