常见浅拷贝方式
Object.assign 方法
- 如果目标对象和源对象有同名属性,或者多个源对象有同名属性,则后面的属性会覆盖前面的属性。
- 如果该函数只有一个参数,当参数为对象时,直接返回该对象;当参数不是对象时,会先将参数转为对象然后返回。
- 因为 null 和 undefined 不能转化为对象,所以第一个参数不能为 null 或 undefined,会报错。
let target = { a: 1 };
let object2 = { b: 2 };
let object3 = { c: 3 };
Object.assign(target, object2, object3);
console.log(target); // {a: 1, b: 2, c: 3}
手写一个
function cloneByObjAssign(params) {
return Object.assing({}, params);
}
扩展运算符(利用了对象的结构赋值特性)方法
let obj1 = { a: 1, b: { c: 1 } };
let obj2 = { ...obj1 };
obj1.a = 2;
console.log(obj1); //{a:2,b:{c:1}}
console.log(obj2); //{a:1,b:{c:1}}
obj1.b.c = 2;
console.log(obj1); //{a:2,b:{c:2}}
console.log(obj2); //{a:1,b:{c:2}}
手写一个
function cloneByDestructuring(params) {
return { ...params };
}
常见的深拷贝方式
大名鼎鼎的 JSON.stringify()
JSON.parse(JSON.stringify(obj))
是目前比较常用的深拷贝方法之一,它的原理就是利用 JSON.stringify
将 js 对象序列化(JSON 字符串),再使用 JSON.parse
来反序列化 (还原)js 对象。
这个方法可以简单粗暴的实现深拷贝,但是还存在问题,拷贝的对象中如果有函数,undefined
,symbol
,当使用过 JSON.stringify()
进行处理之后,都会消失。
函数库 lodash 的_.cloneDeep 方法
var _ = require('lodash');
var obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3],
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f); // false
手写实现深拷贝函数
function deepClone(params) {
if (!params && typeof params == 'object') {
return;
}
let newObject = Array.isArray(params) ? [] : {};
for (let key in params) {
if (params.hasOneProperty(key)) {
newObject[key] =
typeof params[key] == 'object' ? deepClone(params[key]) : params[key];
}
}
return newObject;
}
参考文章
补充
let a = { a: 1 };
let b = { ...a };
let c = Object.assign({}, a);
a.a = 2;
let d = {a: {b: {c : 1}}};
let e = {...d};
let f = Object.assign({}, d);
d.a.b.c = 2;
为什么 b 和 c 的值不会变,而 e 和 f 的值会变呢?
因为 ...
和 Object.assign
是浅拷贝,只会拷贝一层,而 JSON.parse(JSON.stringify(obj))
是深拷贝,会拷贝所有层级。
e 和 f 的值会变,是因为 b 和 c 是个对象,而对象是引用类型,所以 b 和 c 指向的是同一个对象,有点类似于指针,指向的是同一个引用。