传播语法会创建浅副本还是深副本?

发布于 2025-01-28 06:43:47 字数 1204 浏览 3 评论 0 原文

几天来,我对浅副本和深层副本的真实定义感到非常困惑。

当我阅读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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

同展鸳鸯锦 2025-02-04 06:43:47

变量可以包含一个值(如果具有原始值,例如 1 ),则可以包含一个值(如果对象,例如 {food:“ pasta”} 。只能复制原始类型,并且由于它们不包含属性,因此

如果您将参考文献视为原始值, 则不存在浅层/深度区别。参考。 “复制”是A value 的副本,

参考不被视为非主要值的值,有三种不同的方案:

  • 核心发行 。 /代码>,仅指向同一对象;它反映在副本中,但这是错误的:没有副本,只有一个对象。无论您从哪个参考访问对象,它都是相同的实体。这就像拍皮特先生一样,想知道为什么布拉德对你生气 - 布拉德和皮特先生是同一个人,而不是克隆人。
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 请参阅同一对象, {面粉:1,水: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。

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:

  • Coreferences, as created by b = a, merely point to the same object; if you modify a 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.

let a = {
    food: "pasta",
    contents: {
        flour: 1,
        water: 1
    }
}
let b = a;
a.taste = "good";
a.contents.flour = 2;
console.log(b);

  • Shallow copy makes a copy of an object, but any properties that contain references remain so — resulting in coreferent properties. If you change either object, the other is not affected; but if you change any object that is refered to by a property, you will see the change in the other as well. In this example, you will see b.contents.flour is affected by the change in a (because b.contents and a.contents refer to the same object, { flour: 1, water: 2 }), but a.taste does not exist (since a and b are objects in their own right).

let a = {
    food: "pasta",
    contents: {
        flour: 1,
        water: 1
    }
}
let b = {...a};
a.taste = "good";
a.contents.flour = 2;
console.log(b);

  • Deep copy copies each property as well, recursively, so that there are no coreferences — whatever happens to the original object and its properties, the copy is not affected. Here, both b.taste and b.contents.flour are unaffected by changes in a.

let a = {
    food: "pasta",
    contents: {
        flour: 1,
        water: 1
    }
}
let b = structuredClone(a);
a.taste = "good";
a.contents.flour = 2;
console.log(b);

Note that at this time structuredClone is still pretty new; if any users are using older browsers, you might need to use a polyfill.

冷清清 2025-02-04 06:43:47

传播操作员允许您进行浅副本。要进行深度副本,请使用 structruestclone()方法。

因此,在您的情况下,它看起来会如下:

let a = {
    food: "pasta",
    restaurantName: "myPastPlace"
}

let b = structuredClone(a);

阅读更多: 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:

let a = {
    food: "pasta",
    restaurantName: "myPastPlace"
}

let b = structuredClone(a);

Read more: https://developer.mozilla.org/en-US/docs/Web/API/structuredClone

月下凄凉 2025-02-04 06:43:47

逐步内存可视化(带有示例地址)

初始对象创建:

创建令A = {...}时,JavaScript分配了A及其属性的内存,并且每个对象中的每个对象都有一个地址(例如,六核,用于六核这里的简单性)。

A有一个地址0x001。
内容对象{面粉:1,水:1}嵌套在A内,并在地址0x002中分别存储。

Address     Value
0x001       a → { food: "pasta", contents: 0x002 }
0x002       contents → { flour: 1, water: 1 }

带有Let b = {... a}的浅副本:

使用vread语法让b = {... a},javascript创建一个新的对象b,带有新的内存地址0x003。该顶级对象B具有A原始属性的副本,但是对于嵌套对象,它引用了与A. contents相同的内存位置。

B有自己的地址0x003。
地址相同

Address     Value
0x001       a → { food: "pasta", contents: 0x002 }
0x002       contents → { flour: 1, water: 1 }
0x003       b → { food: "pasta", contents: 0x002 }

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反映了此更新,因为它们引用了相同的内存。

Address     Value
0x001       a → { food: "pasta", contents: 0x002, taste: "good" }
0x002       contents → { flour: 2, water: 1 }
0x003       b → { food: "pasta", contents: 0x002 }

浅副本(如定义:对象的浅副本是一个副本,其属性共享相同的参考与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.

Address     Value
0x001       a → { food: "pasta", contents: 0x002 }
0x002       contents → { flour: 1, water: 1 }

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)

Address     Value
0x001       a → { food: "pasta", contents: 0x002 }
0x002       contents → { flour: 1, water: 1 }
0x003       b → { food: "pasta", 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.

Address     Value
0x001       a → { food: "pasta", contents: 0x002, taste: "good" }
0x002       contents → { flour: 2, water: 1 }
0x003       b → { food: "pasta", contents: 0x002 }

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 in a and vice verse.*

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文