blog
blog copied to clipboard
复杂对象拷贝
我们知道对象是地址引用的,因此在开发时,我们会将对象做一次拷贝再放到处理函数中,避免修改对象而产生的副作用。场景的拷贝有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