ES6 能否使用Object.assign实现深浅拷贝?

答案:当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝。

看例子:
1 普通变量

let obj={name:"zhangsan",colors:["red", "green", "blue"]};  
let obj2=Object.assign({},obj);  
obj2.name='wang';  
console.log(obj2);//name wang colors:["red", "green", "blue"]  
console.log(obj);//name zhangsan colors:["red", "green", "blue"]  

结论:普通变量拷贝可以使用Object.assign

2 引用变量

let obj={name:"zhangsan",colors:["red", "green", "blue"]};  
let obj2=Object.assign({},obj);  
obj2.colors[0]='orange';  
console.log(obj2);//name zhangsan colors:["orange", "green", "blue"]  
console.log(obj);//name zhangsan colors:["orange", "green", "blue"]  

结论:Object.assign对于含有引用类型值的对象无法深拷贝。

3 数组

3.1 普通数组

let colors = ['red','green','blue'];  
let colors2 = Object.assign([],colors);  
colors2[0] = "orange";  
console.log(colors2);//['orange','green','blue']  
console.log(colors);//['red','green','blue'] 

结论:普通数组拷贝可以使用Object.assign

3.2 含有引用类型的值的数组

let colors=['red','green','blue',['football','basketball','volleyball']];  
let colors2=Object.assign([],colors);  
colors2[3][0]="ping-pang";  
console.log(colors2);//['red','green','blue',['ping-pang','basketball','volleyball']]  
console.log(colors);//['red','green','blue',['ping-pang','basketball','volleyball']]  

结论:和上面一样,如果一维数组里面有引用类型的值,则无法深拷贝。

如何实现深拷贝?

1 数据结构中不包含引用类型

使用Object.assign(),{...obj}等效


2020-02-16补充:

引用类型对象的值属于"普通"对象,可以使用{...obj}实现深拷贝,比如

let  _o = { a: [1,2,3], b: function(){return 1}, c: [1,5]};
let o = { ..._o };
// 下面两种修改不会改变_o对象
o.a = [2,2,2];
o.b = function(){return 2};
_o.a; // [123]
_o.b(); //  1

引用类型对象的值属于"引用类型"对象,则不可以使用{...obj}实现深拷贝,比如

let  _o = { a: [1,2,3], b: function(){return 1}, c: [1,[3,3,3]]};
let o = { ..._o };
o.c[1] = [4,4,5];
_o.c; // [1,[4,4,5]]

只包含一层引用的情况可以使用{...obj}实现深拷贝

2 数据结构中包含引用类型,符合JSON规则(不包含functon)

直接使用:JSON.parse(JSON.stringify({xxx:'xxx})),简单粗暴~~~~ .

3 数据结构中既有引用类型,又有function

1 通过jQuery的extend方法实现深拷贝,但是估计较少人使用jQuery了
2 lodash.cloneDeep()实现深拷贝

let obj1 = {
    a: 1,
    b: { f: { g: 1 } },
    c: [1, 2, 3]
};
let obj2 = _.cloneDeep(obj1);

3 使用递归的方式实现深拷贝

function _deepClone(source) {
  let target;
  if (typeof source === 'object') {
    target = Array.isArray(source) ? [] : {}
    for (let key in source) {
      if (source.hasOwnProperty(key)) {
        if (typeof source[key] !== 'object') {
          target[key] = source[key]
        } else {
          target[key] = _deepClone(source[key])
        }
      }
    }
  } else {
    target = source
  }
  return target
}

纤细的一帆风顺
40 声望2 粉丝