浅谈: 关于js中的‘深拷贝与浅拷贝’

---本文此前有诸多错误,修改于2023/10/31,如有别的文章还有错误请联系yctjb1@126.com

图示中mdn有明确说明“现在数组a也被也影响了”。即深层遍历的时候(非只遍历一层),它拷贝的是引用,此时便是浅拷贝。

let a = [[1],[2],[3]];
let b = [...a];
b.shift().shift(); // 浅拷贝的话,此操作会影响a中的内容
console.log(a) // Array [Array [], Array [2], Array [3]]   --受影响
console.log(b) // Array [Array [2], Array [3]]

//========换成普通对象来对上述情况更直观的验证
let a = {a1:{ a2:"a2" }};
let b = {...a};
a.a1.a2 = 'a2_改';
console.log(a) // Object { a1: Object { a2: "a2_改" } }
console.log(b) // Object { a1: Object { a2: "a2_改" } }   --受影响


//========
let a = [['0'],['1']];
let b = [...a];
let c = Object.assign(a);
let d = Object.assign([],a);
a[0][0] = '0-改';
console.log(b) // Array [Array ["0-改"], Array ["1"]]   --受影响
console.log(c) // Array [Array ["0-改"], Array ["1"]]   --受影响
console.log(d) // Array [Array ["0-改"], Array ["1"]]   --受影响

网络上有一个很常见的说法“如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,如果B没变,那就是深拷贝”。

但从展开运算符的例子就可以看出来,js中相当多的方法在只遍历一层的时候是深拷贝,深层遍历的时候是浅拷贝。因此很容易陷入一个'眼见为虚'的陷阱——即使观测到一个方法是深拷贝,它也是在特定条件的下的,比如‘仅仅在只遍历一层、且是基本类型数据’的时候是深拷贝方法。

concat方法与slice方法也是同样,即 扩展运算符、concat、slice 均仅对第一层的'基本数据类型'实现深拷贝

let a = [{a1_1:"A"},'B']
let b = [].concat(a);
let c = a.slice(0);
a[0].a1_1 = 'A改'; // {}非基本类型,发生的是浅拷贝
a[1] = 'B改';
console.log(b) // Array [Object { a1_1: "A改" }, "B"]
console.log(c) // Array [Object { a1_1: "A改" }, "B"]

下面这篇文章很好的从"栈堆基本数据类型引用数据类型"的角度出发去区分深拷贝与浅拷贝,此处暂不做过多阐述

https://www.cnblogs.com/echolun/p/7889848.html

笔者常用的一个深拷贝策略,就是文章中也提到的方法2:

对原对象先进行一次JOSN.stringify处理,再进行一次JSON.parse

let obj = {...}//原对象;

let objClone = JSON.parse(JSON.stringify(obj));

此外 js 也有原生的一个深拷贝方法  structuredClone

structuredClone() - Web API 接口参考 | MDN

let a1 = [['0'],['1']]
let a2 = {'0': { '0-0': '0-0'}}
let b = structuredClone(a1);
let c = structuredClone(a2);
let d = JSON.parse(JSON.stringify(a2))
a1[0][0] = '0改'
a2['0']['0-0'] = '0-0改'
console.log(a1) // Array [Array ["0改"], Array ["1"]]
console.log(a2) // Object { 0: Object { 0-0: "0-0改" } }
console.log(b) // Array [Array ["0"], Array ["1"]]
console.log(c) // Object { 0: Object { 0-0: "0-0" } }
console.log(d) // Object { 0: Object { 0-0: "0-0" } }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

devwolf

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

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

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

打赏作者

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

抵扣说明:

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

余额充值