首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >传播语法是创建一个浅拷贝还是深拷贝?

传播语法是创建一个浅拷贝还是深拷贝?
EN

Stack Overflow用户
提问于 2022-05-12 01:45:00
回答 2查看 594关注 0票数 3

几天来,对于浅薄和深拷贝的真正定义,我感到非常困惑。

当我在浅拷贝上读取mdn文档(https://developer.mozilla.org/en-US/docs/Glossary/Shallow_copy)时,这一切都是有意义的。第一段清楚地解释了什么是浅薄的复制品。医生说

对象的浅拷贝是一个副本,其属性与复制所用的源对象的引用(指向相同的基础值)相同。因此,当您更改源或副本时,还可能导致其他对象也发生更改--因此,您可能会无意中导致对源或副本的更改,这是您所不期望的。

我完全明白那部分。根据我的理解,下面的代码示例是浅拷贝的示例,因为更改源或副本会导致其他对象也发生更改。

代码语言:javascript
运行
复制
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,所有标准的内置对象复制操作(扩展语法、Array.prototype.concat()、Array.prototype.slice()、Array.from()、Object.assign()和Object.create())都创建浅拷贝而不是深拷贝。

代码语言:javascript
运行
复制
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
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-05-12 02:20:54

变量可以包含一个值(在原始值的情况下,比如1),也可以包含一个引用(对于对象,比如{ food: "pasta" } )。基元类型只能复制,而且由于它们不包含属性,因此不存在浅/深区分。

如果将引用本身视为原语值,则b = a是引用的副本。但是,由于JavaScript不允许您直接访问引用(就像C一样,等效的概念是指针),将引用复制为“复制”是误导和混淆的。在JavaScript上下文中,“复制”是值的副本,而引用不被视为值。

对于非原始值,有三种不同的方案:

  • Coreferences (由b = a创建)仅指向同一个对象;如果以任何方式修改a,则b将受到相同的影响。直观地,您会说,您修改的任何对象都反映在副本中,但这是错误的:没有副本,只有一个对象。不管您从哪个引用访问对象,它都是同一个实体。这就像扇皮特的耳光,想知道为什么布拉德会生你的气--布拉德和皮特是同一个人,而不是克隆人。--

代码语言:javascript
运行
复制
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.contentsa.contents引用相同的对象{ flour: 1, water: 2 }),但是a.taste并不存在(因为ab本身就是对象)。

代码语言:javascript
运行
复制
let a = {
    food: "pasta",
    contents: {
        flour: 1,
        water: 1
    }
}
let b = {...a};
a.taste = "good";
a.contents.flour = 2;
console.log(b);

  • 还递归地复制每个属性,以便不存在共同引用--无论原始对象及其属性发生什么变化,副本都不会受到影响。在这里,a.

的变化不影响b.tasteb.contents.flour

代码语言:javascript
运行
复制
let a = {
    food: "pasta",
    contents: {
        flour: 1,
        water: 1
    }
}
let b = structuredClone(a);
a.taste = "good";
a.contents.flour = 2;
console.log(b);

请注意,此时structuredClone仍然是非常新的;如果有任何用户正在使用旧的浏览器,则可能需要使用多边形填充。

票数 5
EN

Stack Overflow用户

发布于 2022-05-12 01:54:45

扩展操作符允许您做一个浅拷贝。若要进行深度复制,请使用structuredClone()方法。

所以在你的例子中,它看起来是这样的:

代码语言:javascript
运行
复制
let a = {
    food: "pasta",
    restaurantName: "myPastPlace"
}

let b = structuredClone(a);

阅读更多:https://developer.mozilla.org/en-US/docs/Web/API/structuredClone

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72209243

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档