Spread Syntax 创建的是浅拷贝还是深拷贝?
Does Spread Syntax create a shallow copy or a deep copy?
几天来我对浅拷贝和深拷贝的真正定义感到非常困惑。
当我在浅拷贝上阅读 mdn 文档 (https://developer.mozilla.org/en-US/docs/Glossary/Shallow_copy) 时,这一切都说得通了。第一段清楚地解释了什么是浅拷贝。文档说
A shallow copy of an object is a copy whose properties share the same references (point to the same underlying values) as those of the source object from which the copy was made. As a result, when you change either the source or the copy, you may also cause the other object to change too — and so, you may end up unintentionally causing changes to the source or copy that you don't expect.
我完全明白了那部分。根据我的理解,下面的代码示例是浅拷贝的示例,因为更改源或副本会导致其他对象也发生更改。
let a = {
food: "pasta",
restaurantName: "myPastPlace"
}
let b = a
b.food = "hamburger"
console.log(b.food) //hamburger
console.log(a.food) //hamburger
所以,令人困惑的部分是当我使用扩展语法制作副本时。这是深拷贝还是浅拷贝?因为对于第一层深度,对我来说,传播语法(运算符)正在制作深层副本。但是,MDN 文档说传播语法创建的是浅拷贝而不是深拷贝。
In JavaScript, all standard built-in object-copy operations (spread syntax, Array.prototype.concat(), Array.prototype.slice(), Array.from(), Object.assign(), and Object.create()) create shallow copies rather than deep copies.
let a = {
food: "pasta",
restaurantName: "myPastPlace"
}
let b = {...a}
console.log(b)
b.food = "hamburger"
console.log(b.food) //hamburger
console.log(a.food) //pasta
传播运算符允许您进行浅拷贝。要进行深拷贝,请使用 structuredClone()
方法。
所以在你的情况下它看起来像这样:
let a = {
food: "pasta",
restaurantName: "myPastPlace"
}
let b = structuredClone(a);
阅读更多:https://developer.mozilla.org/en-US/docs/Web/API/structuredClone
一个变量可以包含一个值(对于原始值,如 1
),或一个引用(对于对象,如 { food: "pasta" }
)。原始类型只能被复制,由于它们不包含任何属性,因此 shallow/deep 区别不存在。
如果您将引用本身视为原始值,b = a
是 引用 的副本。但是由于 JavaScript 不让您直接访问引用(就像 C 那样,其中等效的概念是指针),将复制引用称为“复制”是一种误导和混淆。在 JavaScript 的上下文中,“复制”是 值 的副本,引用不被视为值。
对于 non-primitive 值,存在三种不同的情况:
b = a
创建的共引用仅指向同一个对象;如果您以任何方式修改 a
,b
也会受到同样的影响。直觉上你会说无论你修改哪个对象都会反映在副本中,但这是错误的:没有副本,只有一个对象。无论您从哪个引用访问对象,它都是同一个实体。这就像扇皮特先生耳光,想知道布拉德为什么生你的气 — 布拉德和皮特先生是同一个人,而不是克隆人。
let a = {
food: "pasta",
contents: {
flour: 1,
water: 1
}
}
let b = a;
a.taste = "good";
a.contents.flour = 2;
console.log(b);
- 浅拷贝复制了一个对象,但任何包含引用的属性都保持原样——导致引用属性。如果您更改其中一个对象,另一个不会受到影响;但是,如果您更改 属性 引用的任何对象,您也会看到另一个对象的更改。在此示例中,您会看到
b.contents.flour
受到 a
中更改的影响(因为 b.contents
和 a.contents
指的是同一个对象,{ flour: 1, water: 2 }
),但是a.taste
不存在(因为 a
和 b
本身就是对象)。
let a = {
food: "pasta",
contents: {
flour: 1,
water: 1
}
}
let b = {...a};
a.taste = "good";
a.contents.flour = 2;
console.log(b);
- 深拷贝也会递归地拷贝每个 属性,因此没有共指——无论原始对象及其属性发生什么,拷贝都不会受到影响。这里,
b.taste
和 b.contents.flour
都不受 a
. 变化的影响
let a = {
food: "pasta",
contents: {
flour: 1,
water: 1
}
}
let b = structuredClone(a);
a.taste = "good";
a.contents.flour = 2;
console.log(b);
请注意,此时 structuredClone
仍然很新;如果任何用户使用旧版浏览器,您可能需要使用 polyfill。
几天来我对浅拷贝和深拷贝的真正定义感到非常困惑。
当我在浅拷贝上阅读 mdn 文档 (https://developer.mozilla.org/en-US/docs/Glossary/Shallow_copy) 时,这一切都说得通了。第一段清楚地解释了什么是浅拷贝。文档说
A shallow copy of an object is a copy whose properties share the same references (point to the same underlying values) as those of the source object from which the copy was made. As a result, when you change either the source or the copy, you may also cause the other object to change too — and so, you may end up unintentionally causing changes to the source or copy that you don't expect.
我完全明白了那部分。根据我的理解,下面的代码示例是浅拷贝的示例,因为更改源或副本会导致其他对象也发生更改。
let a = {
food: "pasta",
restaurantName: "myPastPlace"
}
let b = a
b.food = "hamburger"
console.log(b.food) //hamburger
console.log(a.food) //hamburger
所以,令人困惑的部分是当我使用扩展语法制作副本时。这是深拷贝还是浅拷贝?因为对于第一层深度,对我来说,传播语法(运算符)正在制作深层副本。但是,MDN 文档说传播语法创建的是浅拷贝而不是深拷贝。
In JavaScript, all standard built-in object-copy operations (spread syntax, Array.prototype.concat(), Array.prototype.slice(), Array.from(), Object.assign(), and Object.create()) create shallow copies rather than deep copies.
let a = {
food: "pasta",
restaurantName: "myPastPlace"
}
let b = {...a}
console.log(b)
b.food = "hamburger"
console.log(b.food) //hamburger
console.log(a.food) //pasta
传播运算符允许您进行浅拷贝。要进行深拷贝,请使用 structuredClone()
方法。
所以在你的情况下它看起来像这样:
let a = {
food: "pasta",
restaurantName: "myPastPlace"
}
let b = structuredClone(a);
阅读更多:https://developer.mozilla.org/en-US/docs/Web/API/structuredClone
一个变量可以包含一个值(对于原始值,如 1
),或一个引用(对于对象,如 { food: "pasta" }
)。原始类型只能被复制,由于它们不包含任何属性,因此 shallow/deep 区别不存在。
如果您将引用本身视为原始值,b = a
是 引用 的副本。但是由于 JavaScript 不让您直接访问引用(就像 C 那样,其中等效的概念是指针),将复制引用称为“复制”是一种误导和混淆。在 JavaScript 的上下文中,“复制”是 值 的副本,引用不被视为值。
对于 non-primitive 值,存在三种不同的情况:
b = a
创建的共引用仅指向同一个对象;如果您以任何方式修改a
,b
也会受到同样的影响。直觉上你会说无论你修改哪个对象都会反映在副本中,但这是错误的:没有副本,只有一个对象。无论您从哪个引用访问对象,它都是同一个实体。这就像扇皮特先生耳光,想知道布拉德为什么生你的气 — 布拉德和皮特先生是同一个人,而不是克隆人。
let a = {
food: "pasta",
contents: {
flour: 1,
water: 1
}
}
let b = a;
a.taste = "good";
a.contents.flour = 2;
console.log(b);
- 浅拷贝复制了一个对象,但任何包含引用的属性都保持原样——导致引用属性。如果您更改其中一个对象,另一个不会受到影响;但是,如果您更改 属性 引用的任何对象,您也会看到另一个对象的更改。在此示例中,您会看到
b.contents.flour
受到a
中更改的影响(因为b.contents
和a.contents
指的是同一个对象,{ flour: 1, water: 2 }
),但是a.taste
不存在(因为a
和b
本身就是对象)。
let a = {
food: "pasta",
contents: {
flour: 1,
water: 1
}
}
let b = {...a};
a.taste = "good";
a.contents.flour = 2;
console.log(b);
- 深拷贝也会递归地拷贝每个 属性,因此没有共指——无论原始对象及其属性发生什么,拷贝都不会受到影响。这里,
b.taste
和b.contents.flour
都不受a
. 变化的影响
let a = {
food: "pasta",
contents: {
flour: 1,
water: 1
}
}
let b = structuredClone(a);
a.taste = "good";
a.contents.flour = 2;
console.log(b);
请注意,此时 structuredClone
仍然很新;如果任何用户使用旧版浏览器,您可能需要使用 polyfill。