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

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

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

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

浅拷贝

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;

  

 

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

       

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

 

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

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

   

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

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

    2)手写一个深拷贝方法

猜你喜欢

转载自www.cnblogs.com/lyraLee/p/10697055.html
今日推荐