js 对象的深拷贝, 与浅拷贝

在学习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);
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

厚渡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值