Javascript 浅拷贝 - 什么是浅拷贝?

2025-06-07

Javascript 浅拷贝 - 什么是浅拷贝?

浅拷贝深拷贝是 JavaScript 中经常出现的术语,如果你以前从未听说过,可能会感到困惑。我们经常听到像slicefilter这样的数组方法对原始数组进行浅拷贝。

JavaScript 中的浅拷贝是什么?

数组或对象的浅拷贝是指它们在内存中具有相同的引用。这意味着,如果你更改浅拷贝,它也可能更改原始拷贝。我说“可能”,是因为情况并非总是如此。

让我们看一个使用的示例slice

let arrayOne = [ '⚡️', '🔎', '🔑', '🔩' ];
let arrayOneSlice = arrayOne.slice(2, 3);  

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

这里我们有一个数组,然后将其赋值slice给变量arrayOneSlice。这两个数组在内存中具有相同的引用,因为slice是它们的浅拷贝。所以如果我们尝试更新arrayOneSlice,也会受到影响arrayOne,对吗?

let arrayOne = [ '⚡️', '🔎', '🔑', '🔩' ];
let arrayOneSlice = arrayOne.slice(2, 3);  

// Update arrayOneSlice
arrayOneSlice[2] = '⚡️'

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

但事实并非如此——因为我们使用了方括号表示法,JavaScript 会将其解释为将新值放入[2]位置。所以只有arrayOneSlice被更新——这也是有充分理由的。虽然 '🔑' 位于[2]中的位置arrayOne,但它位于[0]中的位置arrayOneSlice。这可能会让人误以为这两个数组是副本,并且彼此独立——但事实并非如此。请考虑以下示例:

let arrayOne = [ { items: [ '🔎' ]}, '🔎', '🔑', '🔩' ];
let arrayOneSlice = arrayOne.slice(0, 3);  

// Update arrayOneSlice
arrayOneSlice[0].items = [ '⚡️' ]

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

这里,我们更新了arrayOneSlice[0].items,并且它在两个数组上都更新了,因为items存在于两个数组的同一位置,并且我们没有赋新值,而是使用点.符号来更新现有属性。在 JavaScript 中,这会同时更新原始值和我们使用 创建的副本slice

使用浅拷贝时需要记住的要点是,调整一个值可能会影响你试图复制的原始值——内存中的引用是相同的,而引用指向的是数组的值——所以你必须更加小心。你肯定不想出现意想不到的情况,即数组的原始值和副本值没有按照你预期的那样同步更新。

那么如何在 Javascript 中进行深度复制?

JavaScript 一直以来都不太擅长处理深拷贝。JavaScript 中的大多数方法,例如三点语法或扩展语法只能进行浅拷贝。Object.create()Object.assign()Array.from()

不过,深层复制在内存中有不同的引用,所以使用时不必担心改变原始值。这在我们想要避免这种情况时非常有用。

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

let myArray = [ 1, 2, 3, 4 ];
let deepCopy = JSON.parse(JSON.stringify(myArray));
Enter fullscreen mode Exit fullscreen mode

但这不一定是最好的方法。你也可以使用以下structuredClone()函数进行深层复制:

let myArray = [ 1, 2, 3, 4 ];
let deepCopy = structuredClone(myArray);
Enter fullscreen mode Exit fullscreen mode

现在我们已经使用深层复制创建了新的数组,我们不再需要担心在更改副本时弄乱原始数组。

结论

浅拷贝相当令人困惑,也是 JavaScript 中众多怪癖之一。理解它们可以帮你在以后的调试中省去很多麻烦,而使用深拷贝则是避免这些问题的好方法。

文章来源:https://dev.to/smpnjn/javascript-shallow-copy-what-is-a-shallow-copy-1pc5
PREV
使用 React Portals 将组件传输到任何地方
NEXT
如何撤消 git pull