一张图理解深拷贝和浅拷贝的区别

285 阅读2分钟

这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战

背景

学习前端三个月了,准备刷刷面试题,总结总结,一天几道面试题,向大厂进军。

问题

深拷贝浅拷贝的区别?如何实现一个深拷贝?

解析:

数据的基本类型

我们大家都知道,js中存在两大数据类型:

  • 基本类型
  • 引用类型

基本类型数据保存在栈内存中 引用类型数据保存在堆内存中,引用数据类型的变量是一个指向堆内存的的实际引用地址,保存在栈中。

可以看图:

image.png

浅拷贝

浅拷贝,这里一定要理解拷贝的概念,拷贝是克隆一份新的出来。 浅拷贝与深拷贝的区别是拷贝的层级深度不一样。

如果属性是基本数据类型,拷贝就是基本数据类型的值,如果是引用类型,拷贝的就是内存地址。

在js中,存在浅拷贝的是:

  • Object.assign
  • Array.prototype.slice()Array.prototype.concat()
  • 使用ES6的扩展运算符实现复制

例子:

 //Object.assign
 var obj={name:"qxz",age:45,cc:{c:2}};
 var newObj=Object.assign({},obj);
 
 //扩展运算符
 var c={a:{c:1,b:2},d:{f:3,e:3}};
 var ff={...c};

自己实现一个浅拷贝:


    function clone(obj) {
        const newObj = {};
        for(let prop in obj) {
            if(obj.hasOwnProperty(prop)){
                newObj[prop] = obj[prop];
            }
        }
        return newObj;
    }

深拷贝

深拷贝是开辟一个新的栈,两个对象的属性完全相同。修改其中一个对象的值,另外一个不受影响。

常见的深拷贝:

  • _.cloneDeep(value)
  • jQuery.extend()
  • JSON.stringify() 对undefined,日期,symbol等会存在问题。
  • 手写递归

例子:

//lodash
var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]); //false

//JSON.stringify()

const newObj=JSON.parse(JSON.stringify(objects));

手动递归实现一个:


    function deepClone(obj, hash = new WeakMap()) {
      if (obj === null) return obj; // 如果是null或者undefined我就不进行拷贝操作
      if (obj instanceof Date) return new Date(obj);
      if (obj instanceof RegExp) return new RegExp(obj);
      // 可能是对象或者普通的值  如果是函数的话是不需要深拷贝
      if (typeof obj !== "object") return obj;
      // 是对象的话就要进行深拷贝
      if (hash.get(obj)) return hash.get(obj);
      let cloneObj = new obj.constructor();
      // 找到的是所属类原型上的constructor,而原型上的 constructor指向的是当前类本身
      hash.set(obj, cloneObj);
      for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
          // 实现一个递归拷贝
          cloneObj[key] = deepClone(obj[key], hash);
        }
      }
      return cloneObj;
    }

区别,一张图搞定

image.png

image.png

结语

一步一步慢慢来,踏踏实实把活干!