对象赋值的时候,其实是拷贝了对象的地址。所以改变一方,其他地方也都会改变。
let p1 = {
age: 18
};
let p2 = p1;
p2.age = 20;
console.log(p1.age); // 20
浅拷贝
Object.assign和展开运算符...可以实现浅拷贝。
浅拷贝会拷贝对象中的所有属性到新对象中,如果属性值是对象,则拷贝的是对象的地址。所以还是存在修改了一处,其他地方也会改变的问题。
let obj = {
a: 1,
b: [1,2,3]
};
let newObj = Object.assign({},obj);
// let newObj = {...obj};
obj.a = 2;
console.log(newObj.a); // 1 属性值为非对象时,浅拷贝可以解决问题
obj.b.pop();
console.log(newObj.b);// [1,2] 属性值为对象时,浅拷贝只是拷贝了对象的地址,还是存在问题
深拷贝
彻底解决拷贝对象会共享数据的问题。
- 使用JSON.parse(JSON.stringify(obj))实现深拷贝
let obj = {
a: 1,
b: [1,2,3]
};
let newObj = JSON.parse(JSON.stringify(obj));
上述方法会忽略掉undefined和函数。且不能深拷贝存在循环引用的对象。
let obj = {
a: 1,
b: {
c: 2,
d: 3,
},
}
obj.c = obj.b
obj.b.c = obj.c
let newObj = JSON.parse(JSON.stringify(obj))
console.log(newObj)
- 不包含函数的情况下,可以使用MessageChannel
let obj = {
a: 1,
b: {
c: 2,
d: 3,
},
e: undefined
};
obj.c = obj.b;
obj.b.c = obj.c;
function deepClone(obj) {
return new Promise(resolve => {
const { port1, port2 } = new MessageChannel();
port2.onmessage = res => resolve(res.data);
port1.postMessage(obj);
});
}
let newObj;
let setNewObj = async () => {
newObj = await deepClone(obj);
console.log(newObj);
}
setNewObj();
- 自己实现简单的深拷贝,可以使用loadsh的深拷贝函数
function deepClone(obj) {
if(!isObject(obj)){
throw new Error("非对象");
}
function isObject(o) {
return typeof o === 'object' && o !== null;
}
let newObj = Array.isArray(obj) ? [] : {};
Object.keys(obj).forEach(key => {
newObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key];
});
return newObj;
}
let obj = {
a: 1,
b: [1,2,3]
};
let newObj = deepClone(obj);