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