对于浅拷贝和深拷贝的真正定义,我已经困惑了好几天了.

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

对象的浅层副本是一个副本,其属性与从中创建副本的源对象的属性共享相同的引用(指向相同的基础值).因此,当您更改源或副本时,也可能会导致其他对象也发生更改——因此,您可能会无意中导致对源或副本的更改超出预期.

我完全明白了.据我所知,下面的代码示例是浅拷贝的示例.因为更改源或副本都会导致另一个对象也发生更改.

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

let b = a

b.food = "Hamburger"

console.log(b.food) //hamburger
console.log(a.food) //hamburger

所以,令人困惑的是,当我使用spread语法制作副本时.这是深拷贝还是浅拷贝?因为对于第一级deep,对我来说,扩展语法(操作符)是一个深度复制.然而,Mdn文档表示,spread语法创建的是浅拷贝,而不是深拷贝.

在JavaScript中,所有标准的内置对象复制操作(扩展语法、Array.prototype.concat()、数组).原型slice(),array.from(),对象.assign()和对象.create())创建浅拷贝而不是深拷贝.

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

推荐答案

变量可以包含一个值(对于基元值,如1),也可以包含一个引用(对于对象,如{ food: "pasta" }).基元类型只能复制,因为它们不包含属性,所以不存在浅/深的区别.

如果将引用本身视为基本值,则b = areference的副本.但是,由于JavaScript不允许您直接访问引用(就像C一样,其等效概念是指针),因此将复制引用称为"复制"是误导和混淆的.在JavaScript上下文中,"copy"是value的副本,引用不被视为值.

对于非原始值,有三种不同的情况:

  • b = a创建的共指仅仅指向同一个对象;如果以任何方式修改ab也会受到相同的影响.直觉上你会说,无论你修改哪个对象,它都会反映在副本中,但这是错误的:没有副本,只有一个对象.无论从哪个引用访问对象,它都是同一个实体.这就像打了皮特先生一巴掌,想知道为什么布拉德会生你的气——布拉德和皮特先生是同一个人,而不是克隆人.

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本身就是对象).

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

  • 深度复制也会递归地复制每个属性,这样就不会有共引用——无论原始对象及其属性发生什么变化,复制都不会受到影响.在这里,b.tasteb.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.

Javascript相关问答推荐

当试图显示小部件时,使用者会出现JavaScript错误.

Chart.js 4.4.2,当悬停在一个数据点上时,如何在工具提示中拥有多个数据点/标签?

虚拟滚动实现使向下滚动可滚动到末尾

Html文件和客户端存储的相关问题,有没有可能?

您能在卸载程序(QtInsteller框架)上添加WizardPage吗?

如何从HTML对话框中检索单选项组的值?

400 bad request error posting through node-fetch

面对代码中的错误作为前端与后端的集成

处理TypeScrip Vue组件未初始化的react 对象

如何在TransformControls模式下只保留箭头进行翻译?

Chart.js Hover线条在鼠标离开时不会消失

在将元素追加到DOM之前,createElement()是否会触发回流?混淆abt DocumentFragment行为

限制数组中每个元素的长度,

如果查询为空,则MongoDB将所有文档与$in匹配

通过ng-绑定-html使用插入的HTML中的函数

如何使用Angular JS双击按钮

查找函数句柄的模块/文件

.Remove()函数不适用于MongoDB

我正在用JS编码一个链表,而我编写的一个Prepreend函数并没有按照我的预期工作

Set scale jquery