blog icon indicating copy to clipboard operation
blog copied to clipboard

复杂对象拷贝

Open whizbz11 opened this issue 5 years ago • 0 comments

我们知道对象是地址引用的,因此在开发时,我们会将对象做一次拷贝再放到处理函数中,避免修改对象而产生的副作用。场景的拷贝有object.assign、利用 ES6 的 对象解构运算、JSON的parse和stringify、Immutable、loadsh中deepclone方法。

浅拷贝

  • Object.assign()
Object.assign(target, ...sources)

其中 target 是目标对象,sources 是源对象,可以有多个,返回修改后的目标对象 target。

如果目标对象中的属性具有相同的键,则属性将被源对象中的属性覆盖。后来的源对象的属性将类似地覆盖早先的属性。

  • 利用 ES6 的 对象解构运算
var  obj =  {
    name:  'chris'  ,
    sex:  'male'  ,
    age:  26  ,
    son: {
        sonname:  '大熊'  ,
        sonsex:  'male'  ,
        sonage:  1  }
};   var  {name, sex, age, son} =  obj;
console.log(name  + ' ' + sex + ' ' + age);  //   chris male 26  console.log(son);  //   { sonname: '大熊', sonsex: 'male', sonage: 1 }
//给son变量的sonage赋值,会影响到obj这个对象里面的son.sonage
son.sonage=1212

console.log(obj.son.sonage); //1212

深拷贝

  • JSON的parse和stringify

最原始又有效的做法便是利用 JSON.parse 将该对象转换为其 JSON 字符串表示形式,然后将其解析回对象:

const deepClone(obj) => JSON.parse(JSON.stringify(obj));

利用JSON.stringify 将js对象序列化(JSON字符串),再使用JSON.parse来反序列化(还原)js对象。

对于大部分场景来说,除了解析字符串略耗性能外(其实真的可以忽略不计),确实是个实用的方法。但是尴尬的是它不能处理循环对象(父子节点互相引用)的情况,而且也无法处理对象中有 function、NAN、undefined、正则等情况。

  • loadsh中_.cloneDeep(value)方法 lodash的cloneDeep里面需要处理的逻辑分支比较多,实现代码由有上百行。虽然可以能够很方便的拷贝对象,但是一旦拷贝一些很复杂的对象就有可能报错。不建议使用

  • Immutable

如果需要频繁地操作一个复杂对象,每次都完全深拷贝一次的话效率太低了。大部分场景下都只是更新了这个对象一两个字段,其他的字段都不变,对这些不变的字段的拷贝明显是多余的。

Immutable Data 就是一旦创建,就不能再被更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象.在操作对象的时候只 clone 变化的节点和其祖先节点,其他的保持不变,实现 结构共享(structural sharing)。

let obj = Immutable.fromJS({
    name: 'oldname',
    son: {
        name: 'oldsonname'
    }
});

let obj1 = obj.set('name', 'newname');

// 对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象
console.log(obj.get('name'), obj1.get('name')); // oldname, newname  
console.log(obj === obj1); //  false

//如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享。
console.log(obj.get('son') === obj1.get('son')); //true

whizbz11 avatar Dec 25 '19 16:12 whizbz11