在学习js的时候,最容易翻车的就是对象没有深拷贝, 而出现莫名其妙的bug。
一时间还在想是不是逻辑有问题。
本期,我花了点时间总结归纳了一下
我们先定义一个对象 作为被克隆的对象
let obj1 = {
name: "dwp1",
age: 18,
faceScore: "up",
};
浅拷贝
let obj3 = obj1;
// 这个时候 obj1, obj3 是一样的, 没有问题
console.log("obj1, obj3 是一样的, 没有问题", obj1, obj3);
obj3.name = 'dwp3';
// obj1, obj3 还是一样的, 问题就来了
console.log("obj1, obj3 还是一样的, 问题就来了", obj1, obj3);
// 为什么 obj1.name 也是 dwp3 了呢
如何解决? 深拷贝!
// 那我这样写
let obj4 = {};
for (let key in obj1) {
console.log(key);
obj4[key] = obj1[key];
}
// 这个时候 obj1, obj4 是一样的, 没有问题
console.log("obj1, obj4 是一样的, 没有问题", obj1, obj4);
obj4.name = 'dwp4';
// obj1, obj4 发现这两个对象, 分开了
console.log("obj1, obj4 是一样的, No problem", obj1, obj4);
但这会不会太麻烦了? 我们这样
let obj5 = JSON.parse(JSON.stringify(obj1));
// 这个时候 obj1, obj5 是一样的, 没有问题
console.log("obj1, obj5 是一样的, 没有问题", obj1, obj5);
obj5.name = "dwp5";
// obj1, obj5 发现这两个对象, 分开了 也是没什么问题的
console.log("obj1, obj5 还是一样的, No problem", obj1, obj5);
但这会不会太麻烦了? 我们这样
var obj6 = { ...obj1 };
// 这个时候 obj1, obj6 是一样的, 没有问题
console.log("obj1, obj6 是一样的, 没有问题", obj1, obj6);
obj6.name = "dwp6";
// obj1, obj6 发现这两个对象, 分开了 也是没什么问题的
console.log("obj1, obj6 还是一样的, No problem", obj1, obj6); // 这是真的嘛?
我们再定义一个对象测试一下
let obj8 = {};
// 构建一个复制的对象
for (let i = 1; i < 70; i++) {
if (i < 10) {
obj8["objs" + i] = i;
} else if (i < 40) {
obj8["objs" + i] = "str" + i;
} else if (i < 50) {
obj8["objs" + i] = { ["name" + i]: i };
} else if (i < 60) {
obj8["objs" + i] = [i, i + 1, i + 2, i + 3];
} else {
obj8["objs" + i] = [
{ ["name" + i]: i },
{ ["name" + i]: i + 1 },
{ ["name" + i]: i + 2 },
];
}
}
let obj10 = JSON.parse(JSON.stringify(obj8));
let obj9 = { ...obj10 };
console.log(obj8);
console.log("obj8, obj9 是一样的, 没有问题", obj8, obj9);
obj9.objs40.name40 = "dwp6";
obj9.objs10 = "dwp6";
console.log("obj10, obj9 还是一样的? 不是! 对象中的对象,仍然是浅拷贝", obj10, obj9);
// 转字符串再转对象的方法 是最好用的
obj10.objs40.name40 = "dwp6";
obj10.objs10 = "dwp6";
console.log("obj8, obj10 还是一样的? 是! 对象中的对象,已然是深拷贝", obj8, obj10);
总结
有以上例子我们可以得出,克隆对象的最好办法还是 JSON.parse(JSON.stringify(obj1));
将对象转字符串再转回来。
虽然{...obj1}
这种对象解析的方式也可以达到伪克隆
的目的, 这个名称是我自己意淫的, 但克隆并不彻底。
而且在使用中也会出现一些问题, 我踩过的坑我也没怎么找到原因, 只是建议不要使用这种方式去克隆对象而已。 其他用途还是挺好用的。
欢迎关注留言加评论, 谢谢!
------------------------------------------------------------补充----------------------------------------------------
之前大家不明白为什么我说了那个是 伪克隆
ps:
let obj = {name: 'obj1', dwp: {chi: 'dwp cih'}};
// let obj = {name: 'obj1', dwp:'dwp1'};
// let obj = {name: 'obj1', dwp:'dwp1'};
let cyObj1 = {...obj};
cyObj1.name = 'cyObj1';
cyObj1.dwp.chi = 'dwp.chi'; // 注意这个时候 得到的是一个对象地址
console.log(cyObj1);
let cyObj2 = JSON.parse(JSON.stringify(obj));
cyObj2.name = 'cyObj2';
console.log(cyObj2);
console.log('obj', obj);