几天来,我对浅副本和深层副本的真实定义感到非常困惑。
当我阅读MDN文档时()在浅副本上,这都是有道理的。第一段清楚地说明了什么是浅副本。文档说
对象的浅副本是一个副本,其属性共享与制作副本的源对象相同的参考(指向基础值相同的基础值)。结果,当您更改源或副本时,您也可能会导致另一个对象更改 - 因此,您可能无意中会导致对源的更改或您不期望的副本。
我完全明白了那部分。从我的理解来看,以下代码示例是浅副本的示例,因为更改源或副本会导致另一个对象也更改。
let a = {
food: "pasta",
restaurantName: "myPastPlace"
}
let b = a
b.food = "hamburger"
console.log(b.food) //hamburger
console.log(a.food) //hamburger
因此,令人困惑的部分是,当我使用差异语法制作副本时。这是深副本还是浅副本?因为对于我的第一层,对我来说,传播语法(操作员)正在进行深层副本。但是,MDN DOC说,传播语法会创建浅副本而不是深副本。
在JavaScript中,所有标准内置的对象拷贝操作(vrable语法,array.prototype.concat(),array.prototype.slice(),array.from(),object.assign()和对象。创建())创建浅副本而不是深副本。
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
I am extremely confused for days now regarding the true definition of a shallow copy and a deep copy.
When I read the mdn docs (https://developer.mozilla.org/en-US/docs/Glossary/Shallow_copy) on shallow copy, it all made sense. The first paragraph clearly explains what a shallow copy is. The docs says
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.
I totally got that part. From my understanding, the below code example is the example of a shallow copy since changing either the source or the copy causes the other object to change too.
let a = {
food: "pasta",
restaurantName: "myPastPlace"
}
let b = a
b.food = "hamburger"
console.log(b.food) //hamburger
console.log(a.food) //hamburger
So, the confusing part was that when I use the spread syntax to make a copy. Is this deep copy or shallow copy? Because for the first level deep, to me, the spread syntax(operator) is making a deep copy. However, the MDN doc says the spread syntax creates a shallow copy rather than a deep copy.
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
发布评论
评论(3)
变量可以包含一个值(如果具有原始值,例如
1
),则可以包含一个值(如果对象,例如{food:“ pasta”}
。只能复制原始类型,并且由于它们不包含属性,因此如果您将参考文献视为原始值, 则不存在浅层/深度区别。参考。 “复制”是A value 的副本,
参考不被视为非主要值的值,有三种不同的方案:
b.contents.flour
受a
的更改影响(因为b.contents
和a .contents
请参阅同一对象,{面粉:1,水:2}
),但是a.taste
不存在(因为a
和b
是对象本身)。b.taste
和b.contents.flour
不受a
中的更改影响。请注意,目前
structuredclone
仍然很新。如果任何用户正在使用较旧的浏览器,则可能需要使用polyfill。A variable can contain either a value (in case of primitive values, like
1
), or a reference (in case of objects, like{ food: "pasta" }
. Primitive types can only be copied, and since they contain no properties, the shallow/deep distinction does not exist.If you considered references themselves as primitive values,
b = a
is a copy of a reference. But since JavaScript does not give you direct access to references (like C does, where the equivalent concept is a pointer), refering to copying a reference as "copy" is misleading and confusing. In context of JavaScript, "copy" is a copy of a value, and a reference is not considered a value.For non-primitive values, there are three different scenarios:
b = a
, merely point to the same object; if you modifya
in any way,b
is affected the same way. Intuitively you'd say that whichever object you modify it is reflected in the copy, but it would be wrong: there is no copy, there is just one object. Regardless of which reference you access the object from, it is the same entity. It is like slapping Mr. Pitt, and wondering why Brad is mad at you — Brad and Mr. Pitt are the same person, not clones.b.contents.flour
is affected by the change ina
(becauseb.contents
anda.contents
refer to the same object,{ flour: 1, water: 2 }
), buta.taste
does not exist (sincea
andb
are objects in their own right).b.taste
andb.contents.flour
are unaffected by changes ina
.Note that at this time
structuredClone
is still pretty new; if any users are using older browsers, you might need to use a polyfill.传播操作员允许您进行浅副本。要进行深度副本,请使用
structruestclone()
方法。因此,在您的情况下,它看起来会如下:
阅读更多: https:/ /developer.mozilla.org/en-us/docs/web/api/structuredclone
The spread operator allows you to make a shallow copy. To make a deep copy, use the
structuredClone()
method.So in your case it would look like this:
Read more: https://developer.mozilla.org/en-US/docs/Web/API/structuredClone
逐步内存可视化(带有示例地址)
初始对象创建:
创建令A = {...}时,JavaScript分配了A及其属性的内存,并且每个对象中的每个对象都有一个地址(例如,六核,用于六核这里的简单性)。
A有一个地址0x001。
内容对象{面粉:1,水:1}嵌套在A内,并在地址0x002中分别存储。
带有Let b = {... a}的浅副本:
使用vread语法让b = {... a},javascript创建一个新的对象b,带有新的内存地址0x003。该顶级对象B具有A原始属性的副本,但是对于嵌套对象,它引用了与A. contents相同的内存位置。
B有自己的地址0x003。
地址相同
butents指向与a.contents(0x002)修改a.taste and a.contents.flour:
当a.taste =“ good”时的 ;添加,A会获得新的特性味道而不会影响B,因为B没有味道。
a.contents.flour = 2;经过修改,更改是在地址0x002上进行的,因此A。contents和B. contents反映了此更新,因为它们引用了相同的内存。
浅副本(如定义:对象的浅副本是一个副本,其属性共享相同的参考)与C ++ 中的“通过参考”概念完全不同。
在“通过引用”中:
b =& a
; b和a在内存上共享相同的地址,*b
中的所有更改均在a
和vice vice Verse中。**Step-by-Step Memory Visualization (With Example Addresses)
Initial Object Creation:
When let a = { ... } is created, JavaScript allocates memory for a and its properties, and each object in memory has an address (e.g., hexadecimal for simplicity here).
a has an address 0x001.
The contents object { flour: 1, water: 1 } is nested within a and stored separately at address 0x002.
Shallow Copy with let b = {...a}:
Using the spread syntax let b = {...a}, JavaScript creates a new object b with a new memory address 0x003. This top-level object b has copies of a's primitive properties, but for nested objects, it references the same memory location as a.contents.
b has its own address 0x003.
b.contents points to the same address as a.contents (0x002)
Modifying a.taste and a.contents.flour:
When a.taste = "good"; is added, a gains a new property taste without affecting b, as b does not have a taste property.
When a.contents.flour = 2; is modified, the change is made at address 0x002, so both a.contents and b.contents reflect this update since they reference the same memory.
Shallow copy (As in definition: A shallow copy of an object is a copy whose properties share the same references ) is completely different from "Pass by reference" concept in C++.
In "Pass by reference":
b=&a
; b and a share the same address on memory, all change in*b
is refelected ina
and vice verse.*