如何理解js中的深拷贝和浅拷贝

小记~

一、什么是深拷贝、浅拷贝?

const A = [1,2,3,4,[5,6]]
浅拷贝:也就是拷贝A对象里面的数据,但是不拷贝A对象里面的子对象
深拷贝:会克隆出一个对象,数据相同,但是引用地址不同(就是拷贝A对象里面的数据,而且拷贝它里面的子对象)

二、深拷贝和浅拷贝有什么区别?

三、深拷贝和浅拷贝如何实现?

浅拷贝:

  1. arr.concat()
test1() {
      const arr = [1, 2, 3, 4, [5, 6]];
      const copy = arr.concat();
      // 改变基本数据类型,不会改变原始值
      copy[0] = 99;
      console.log("改变基本数据类型:", arr);

      // 改变引用类型,改变原始值
      copy[4][1] = 77;
      console.log("改变引用类型:", arr);
    },
  1. Object.assign({}, obj1)
 test2() {
      const obj1 = { x: 1, y: 2 };
      const obj2 = Object.assign({}, obj1);

      obj2.x = 22; //修改obj2.x,改变对象中的基本类型值
      console.log("obj1:", obj1);
      console.log("obj2:", obj2);

      const obj3 = {
        x: 33,
        y: {
          m: 33,
        },
      };
      const obj4 = Object.assign({}, obj3);
      obj4.y.m = 44;
      console.log("浅拷贝:");
      console.log("obj3:", obj3); //{x:33,y:{ m:44}};
      console.log("obj4:", obj4); //{x:33,y:{ m:44}};
    },

深拷贝:

  1. JSON.parse(JSON.stringify(obj1))
test3() {
      const obj1 = {
        x: 1,
        y: {
          m: 1,
        },
      };
      const obj2 = JSON.parse(JSON.stringify(obj1));
      console.log("深拷贝:");
      console.log("obj1:", obj1);//{x:1,y:{ m:1}};
      console.log("obj2:", obj2);//{x:1,y:{ m:1}};

      obj2.y.m = 2;
      console.log("修改obj2.y.m:");
      console.log("obj1:", obj1);//{x:1,y:{ m:1}};
      console.log("obj2:", obj2);//{x:1,y:{ m:2}};
    }

2.递归

    test4() {
      const obj1 = {
        x: {
          m: 1,
        },
        y: undefined,
        z: function add(z1, z2) {
          return z1 + z2;
        },
        a: Symbol("foo"),
      };
      console.log("采用递归方式进行深拷贝:");
      const obj2 = this.deepCopy(obj1);
      obj2.x.m = 2;
      console.log(obj1);
      console.log(obj2);
    },

    // 深拷贝-递归
    deepCopy(obj) {
      // 创建一个新对象
      let result = {};
      let keys = Object.keys(obj),
        key = null,
      temp = null;

      for (let i = 0; i < keys.length; i++) {
        key = keys[i];
        temp = obj[key];
        // 如果字段的值是一个对象则递归操作
        if (temp && typeof temp === "object") {
          result[key] = this.deepCopy(temp);
        } else {
          result[key] = temp;
        }
      }
      return result;
    },

四、使用JSON.parse(JSON.stringfy(obj))深拷贝有什么缺点?

缺点:

  1. obj里面有时间对象,采用JSON.parse(JSON.stringify(obj1))深拷贝之后,时间只是字符串形式,而不是时间对象
test3(){
 var obj3 = {
        name: "a",
        date: [new Date(1536627600000), new Date(1540047600000)],
      };

      var copyedObj3 = JSON.parse(JSON.stringify(obj3));
      console.log(copyedObj3);//{name: "a",date: (2) ["2018-09-11T01:00:00.000Z", "2018-10-20T15:00:00.000Z"]}
}

2.如果obj里面有正则RegExp、Error对象,则序列化的结果将只得到空对象

test5(){
const obj5 = {
        name: "a",
        date: new RegExp("\\w+"),
      };
      const copyedObj5 = JSON.parse(JSON.stringify(obj5));
      console.log("obj5:", obj5);//{name: "a",date: /\w+/}
      console.log("copyedObj5:", copyedObj5);//{name: "a",date: {}}
}

3.如果obj里面有函数、undefined,则序列化的结果会把函数或undefined丢失

test6(){
 const obj6 = {
        name: "a",
        date: function() {
          console.log("我是obj里面的函数");
        },
      };
      const copyedObj6 = JSON.parse(JSON.stringify(obj6));
      console.log("obj6:", obj6);//{name: "a",date:f date()
      console.log("copyedObj6:", copyedObj6);//{name: "a"}

      const obj7 = {
        name: "a",
        date: undefined,
      };
      const copyedObj7 = JSON.parse(JSON.stringify(obj7));
      console.log("obj7:", obj7);//{name: "a", date: undefined}
      console.log("copyedObj7:", copyedObj7);//{name: "a"}
}
  1. 如果obj里面有NaN、Infinity和-Infinity,则序列化的结果会变成null
test8(){
const obj8 = {
        name: "a",
        date: NaN,
      };
      const copyedObj8 = JSON.parse(JSON.stringify(obj8));
      console.log("obj8:", obj8);//{name: "a", date: NaN}
      console.log("copyedObj8:", copyedObj8);{name: "a", date: null}
}

五、深拷贝和浅拷贝涉及到其他知识:

1、什么是JS的基本数据类型和引用类型?有什么区别?

2、什么是堆和栈?有什么区别?

3、堆和栈的数据结构是什么样的?

4、如何理解什么是传值,什么是传址?

5、堆和栈的图示改怎么画?如:Var user = {name:'张三'}