浅拷贝(Shallow Copy) VS 深拷贝(Deep Copy)

时间:2022-10-28 19:52:12

首先,深拷贝和浅拷贝针对的是对象类型(对象,数组,函数)

浅拷贝指的是只是拷贝了对象的引用地址,彼此之间高耦合,一个改变,另一个可能也随之改变;

深拷贝是指只是完整的将变量的值拷贝过来,是一个新的对象,和被拷贝对象解耦合,一个改变,不会影响其它的内容。

浅拷贝

1.最浅的拷贝--对象直接赋值,整个地址拷贝

let a = {
    age: 1
}
let b = a;
a.age = 2
console.log(b.age) // 2

2.一级浅拷贝(无嵌套)--->每个属性的值都是原始类型的值

 1)对象遍历赋值

let copy = function(target,source){
    for(let property in source){
       target[property] = source[property]
    }     
    return target;   
}

 2) 对象合并函数Object.assign({})--复制可遍历属性(元属性enumerable为true)

当Object.assign(obj)只有一个参数时,相当于最浅拷贝,
let copy = Object.assign(obj);
等同于: let copy = obj;
// 注意:当obj的值为原始类型的值(boolean,string,number)时,会将原始值转为包装对象。当obj为undefined或者null时,无法转为对象会报错。

当Object.assign(target, source1, source2,...)有多个参数时,可以将第一个设为空对象{}
let copy = Object.assign({}, source);
等同于:(1)中的对象遍历属性赋值
// 注意: 当source为undefined或者null或者(boolean,number)时,会忽略source;当source为string类型时,会将字符串转为对象 Object.assign({},str) ---> //{0: "a", 1: "b", 2: "c"}

3)扩展运算符(...)和(1)类似

let a = {
    age: 1
}
let b = {...a}
a.age = 2
console.log(b.age) // 1

 注意: 以上三种方法仅限于对象的属性值非对象类型,如果是对象类型,则属性值是对象的属性仅引用地址拷贝

 eg:  let a = {b: {b1: {b2: 3}}, c: {c1: 2}, d: 5};

       1)let target1 = copy({}, a);  

       2)let target2 = Object.assign({},a);

       3)let target3 = {...a};

       当修改a.b = 100; target1,target2,target3都同时修改;

       当修改a.d = 99; target1,target2,target3都保持不变;

深拷贝

为了不出现上面例子中,嵌套关系拷贝只拷贝地址的情况,我们需要遍历到最底层,逐级赋值,实现深拷贝

1.JSON.parse(JSON.stringify())--->可遍历属性

  该方法可以解决大多数的深拷贝问题。

  但是有局限性:

  1)JSON.stringify()忽略属性值为undefined和function类型和Symbol类型的值;
  2) JSON.stringify()序列化值为Regex,Error类型的值会变成空对象{};

  3) JSON.stringify()序列化NaN,Infinity,-Infinity的值会变成null;

浅拷贝(Shallow Copy) VS 深拷贝(Deep Copy)

浅拷贝(Shallow Copy) VS 深拷贝(Deep Copy)

  浅拷贝(Shallow Copy) VS 深拷贝(Deep Copy)

浅拷贝(Shallow Copy) VS 深拷贝(Deep Copy)

浅拷贝(Shallow Copy) VS 深拷贝(Deep Copy)

 浅拷贝(Shallow Copy) VS 深拷贝(Deep Copy)

 3)不能序列化循环引用的对象,会抛出异常

浅拷贝(Shallow Copy) VS 深拷贝(Deep Copy)       

 4)当参数对象有自定义的toJSON()方法时,JSON.stringify()会将该方法的返回值作为最后的参数值,忽然其它的参数。

  浅拷贝(Shallow Copy) VS 深拷贝(Deep Copy)

  5)当参数值为Date对象类型时,因为Date对象有toJSON()方法,则JSON.stringify()会将Date类型的值按照字符串转换,

    然后JSON.parse()去解析JSON字符串,最终会解析成字符串,不会解析成Date类型。

    浅拷贝(Shallow Copy) VS 深拷贝(Deep Copy)

 2.通用的深拷贝方法(解决方法1中的局限问题)

    1)直接使用lodash中的cloneDeep方法

    2)手写一个深拷贝方法