javascript - 使用传播运算符的对象复制实际上是浅的还是深的?

标签 javascript json

我了解传播运算符制作对象的浅拷贝,即克隆对象引用与原始对象相同的引用。
但实际行为似乎是矛盾和令人困惑的。

const oldObj = {a: {b: 10}};

const newObj = {...oldObj};

oldObj.a.b = 2;
newObj  //{a: {b: 2}}
oldObj  //{a: {b: 2}}

上述行为是有道理的,newObj 也通过更新 oldObj 来更新,因为它们引用相同的位置。
const oldWeirdObj = {a:5,b:3};

const newWeirdObj = {...oldWeirdObj};

oldWeirdObj.a=2;
oldWeirdObj      //{a:2,b:3}
newWeirdObj   //{a:5,b:3}

我不明白,为什么 newWeirdObj 不像 oldWeirdObj 那样更新?
如果我没记错的话,他们仍然指的是同一个位置,但为什么更新 oldWeirdObj 不更新 newWeirdObj ?

最佳答案

所以,对于这个问题,你要明白什么是shallow复制和deep复制。

浅拷贝是对象的按位副本,它通过复制原始对象的内存地址来创建新对象。也就是说,它创建了一个内存地址与原始对象相同的新对象。

深拷贝 ,复制所有具有动态分配内存的字段。也就是说,复制对象的每个值都会获得一个新的内存地址,而不是原始对象。

现在,扩展运算符做什么?如果数据没有嵌套,它会深度复制数据。对于嵌套数据,它深度复制嵌套数据的最顶层数据和浅层数据。

在你的例子中,

const oldObj = {a: {b: 10}};
const newObj = {...oldObj};

它深度复制顶级数据,即它提供属性 a , 一个新的内存地址,但它浅拷贝嵌套对象,即 {b: 10}现在仍然指原始的oldObj的内存位置。

如果您不相信我,请查看示例,

const oldObj = {a: {b: 10}, c: 2};
const newObj = {...oldObj};

oldObj.a.b = 2; // It also changes the newObj `b` value as `newObj` and `oldObj`'s `b` property allocates the same memory address.
oldObj.c = 5; // It changes the oldObj `c` but untouched at the newObj



console.log('oldObj:', oldObj);
console.log('newObj:', newObj);
.as-console-wrapper {min-height: 100%!important; top: 0;}


你看 c位于 newObj 的属性(property)未触及。

如何深度复制对象。

我认为有几种方法。一种常见且流行的方法是使用 JSON.stringify()JSON.parse() .

const oldObj = {a: {b: 10}, c: 2};
const newObj = JSON.parse(JSON.stringify(oldObj));

oldObj.a.b = 3;
oldObj.c = 4;

console.log('oldObj', oldObj);
console.log('newObj', newObj);
.as-console-wrapper {min-height: 100%!important; top: 0;}


现在,newObj oldObj 上有全新的内存地址和任何更改不影响newObj .

另一种方法是分配 oldObj属性一一导入newObj的新分配的属性。

const oldObj = {a: {b: 10}, c: 2};
const newObj = {a: {b: oldObj.a.b}, c: oldObj.c};

oldObj.a.b = 3;
oldObj.c = 4;

console.log('oldObj:', oldObj);
console.log('newObj:', newObj);
.as-console-wrapper {min-height: 100%!important; top: 0;} 


有一些库可用于深拷贝。你也可以使用它们。

关于javascript - 使用传播运算符的对象复制实际上是浅的还是深的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61421873/

相关文章:

json - 如何反序列化 java pojo 类中的 json 对象?

javascript - 如何从JSON中获取数据并与页面中的数据进行比较?

sql - 将 mssql openjson 数组类型值结果转换为表?

javascript - 带有数组的 react 形式的primeng复选框

javascript - 事件在replaceWith()后不会触发

javascript - angularjs 过滤器不适用于 i18n 文本

java - 递归方法创建Json对象

json - jq:将对象数组转换为对象

javascript - 在 Node.js 项目上运行客户端 javascript

javascript - 使用 jQuery 交换 Div 背景图像