首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Javascript 中的浅拷贝深拷贝是什么?一文带你搞懂,不再犯错

Javascript 中的浅拷贝深拷贝是什么?一文带你搞懂,不再犯错

作者头像
前端修罗场
发布2023-10-07 19:52:10
发布2023-10-07 19:52:10
44800
代码可运行
举报
文章被收录于专栏:Web 技术Web 技术
运行总次数:0
代码可运行

浅拷贝和深拷贝是Javascript中抛出的术语,如果你以前没有听说过,可能会感到困惑。我们经常听说,像 slicefilter 这样的数组方法会对原始数组进行浅层复制

一个数组或对象的浅层拷贝是指它们在内存中都有相同的引用。这意味着,如果你 改变了浅层拷贝,它也可能改变原始拷贝。我说可能,因为情况并不总是这样的。

让我们看一个使用 slice的例子。

代码语言:javascript
代码运行次数:0
运行
复制
let arrayOne = [ '⚡️', '🔎', '🔑', '🔩' ];
let arrayOneSlice = arrayOne.slice(2, 3);  

console.log(arrayOne); // [ '⚡️', '🔎', '🔑', '🔩' ]
console.log(arrayOneSlice); // [ '🔑' ]

这里我们有一个数组,然后我们在变量 arrayOneSlice 中进行 slice 操作。这两个数组在内存中都有相同的引用,因为 slice 对它们做了一个浅层拷贝。所以如果我们试图更新 arrayOneSlice ,它也会影响 arrayOne ,对吗?

代码语言:javascript
代码运行次数:0
运行
复制
let arrayOne = [ '⚡️', '🔎', '🔑', '🔩' ];
let arrayOneSlice = arrayOne.slice(2, 3);  

// 更新 arrayOneSlice
arrayOneSlice[2] = '⚡️'

console.log(arrayOne); // [ '⚡️', '🔎', '🔑', '🔩' ]
console.log(arrayOneSlice); // [ '🔑', empty, '⚡️' ]

因为我们使用了方括号符号,Javascript把它解释为把一个新的值放到 [2] 的位置。所以只有 arrayOneSlice 被更新了。虽然 '🔑'arrayOne 中处于 [2] 的位置,但它在 arrayOneSlice 中处于 [0] 的位置。这可能会给人一种错觉,认为这两个数组是复制的,并且相互独立。 但事实也并非如此。考虑一下下面的例子。

代码语言:javascript
代码运行次数:0
运行
复制
let arrayOne = [ { items: [ '🔎' ]}, '🔎', '🔑', '🔩' ];
let arrayOneSlice = arrayOne.slice(0, 3);  

// 更新 arrayOneSlice
arrayOneSlice[0].items = [ '⚡️' ]

console.log(arrayOne); // [ { items: [ '⚡️' ]}, '🔎', '🔑', '🔩' ]
console.log(arrayOneSlice); // [ { items: [ '⚡️' ]}, '🔎', '🔑' ]

在这里,我们更新了 arrayOneSlice[0].items,它在两个数组上都被更新了,因为 items 在两个数组的相同位置都存在,而且我们没有分配一个新的值,而是用点.符号来更新一个现有属性。在Javascript中,这同时更新了原始属性和我们用 slice 制作的副本。

对于浅层拷贝,需要记住的主要一点是,调整一个拷贝会影响你试图复制的原件。内存中的引用是相同的,而引用指向数组的值,所以你必须更加小心。你不想做的是产生意想不到的行为,即数组的原始和副本在你期望的时候没有同步更新。

那么,如何在Javascript中进行深度拷贝?

在深层拷贝方面,Javascript历来有一点问题。Javascript中的大多数方法,如三点扩展运算符语法、Object.create()、Object.assign()和Array.from(),都会进行浅层拷贝。

不过,深度拷贝在内存中有不同的引用,所以你不必担心在使用它们的时候会改变原件。这使得它们在我们想避免这种情况时非常有用。

深度拷贝可以通过序列化来实现,或者通过自定义脚本将一个对象或数组的每一部分复制到一个新的对象中,在内存中创建一个新的引用。例如,这将在Javascript中创建一个具有新引用的新数组。

代码语言:javascript
代码运行次数:0
运行
复制
let myArray = [ 1, 2, 3, 4 ];
let deepCopy = JSON.parse(JSON.stringify(myArray));

但这不一定是最好的方法。你也可以使用 structuredClone() 函数来做一个深度拷贝。

代码语言:javascript
代码运行次数:0
运行
复制
let myArray = [ 1, 2, 3, 4 ];
let deepCopy = structuredClone(myArray);

现在我们已经用深度拷贝创建了新的数组,我们不再需要担心在改变拷贝时弄乱了原始数组。

结论

浅层拷贝是相当令人困惑的,也是Javascript的众多怪癖之一。了解它们是什么,可以在将来调试时省去很多麻烦,而使用深度拷贝是避免这些问题的一个好办法。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 那么,如何在Javascript中进行深度拷贝?
  • 结论
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档