为什么在复制数组中更改对象也会影响原始对象中的对象?

IT技术 javascript reactjs ecmascript-6
2021-05-08 06:37:21

在这段代码中,我obj使用展开运算符复制copiedObj. 然后将checked属性值修改false. 但是,当 I 时console.log(obj.checked[0]),它返回 false 而不是 true。而且似乎中的checkedcopiedObj也改变了原始属性值。这是为什么?

const obj = [{id: 1, checked: true}];
const copiedObj = [...obj];
copiedObj.checked[0] = false;
console.log(obj.checked[0]);

3个回答

objcopiedObj是数组,而不是普通对象。更改状态copiedObj(通过checked向其添加属性)不会更改状态,obj因为它们是单独的数组。

但是,两个数组都包含对同一个对象的引用(上面有一个cheecked)。所以如果你这样做:

checkedObj[0].checked = true;

这会改变那个对象的状态,你会看到你是否在obj[0]上查找该对象checkedObj[0]

如果要进行深拷贝以便拥有单独的数组单独的对象,请参阅此问题的答案

由于我 99% 确定你的意思checkedObj[0].checked = true,我将解释这段代码中发生的事情:

// Creates an array containing an object
const obj = [{id: 1, checked: true}];
// Creates a new array that contains the *same* object (NOT a *copy* of it)
const copiedObj = [...obj];
// Sets `checked` on that one object that is in both arrays
copiedObj[0].checked = false;
// Looks at the `checked` property on that one object that is in both arrays
console.log(obj[0].checked);

一步步:

// Creates an array containing an object
const obj = [{id: 1, checked: true}];

在记忆中你有类似的东西

                  +−−−−−−−−−−−−−−−+
obj:Ref44329−−−−−>| (数组) |
                  +−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−+
                  | 0:Ref82445 |−−−>| (对象) |
                  +−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−+
                                     | 编号:1 |
                                     | 检查: 真 |
                                     +−−−−−−−−−−−−−−−−−+

然后当你做

// Creates a new array that contains the *same* object (NOT a *copy* of it)
const copiedObj = [...obj];

你有这样的事情:

                       +−−−−−−−−−−−−−−−+
obj:Ref44329−−−−−−−−−−−>| (数组) |
                       +−−−−−−−−−−−−−−−+   
                       | 0:Ref82445 |−−+
                       +−−−−−−−−−−−−−−+ |
                                        |
                                        | +−−−−−−−−−−−−−−−−−−+
                                        +−−>| (对象) |
                       +−−−−−−−−−−−−−−+ |    +−−−−−−−−−−−−−−−−−−+
 checkedObj:Ref12987−−−>| (数组) | |    | 编号:1 |
                       +−−−−−−−−−−−−−−+ |    | 检查: 真 |
                       | 0: Ref82445 |−−+    +−−−−−−−−−−−−−−−−+
                        +−−−−−−−−−−−−−−+ 

然后当你做

// Sets `checked` on that one object that is in both arrays
copiedObj[0].checked = false;

它改变了两个数组指向的对象

                       +−−−−−−−−−−−−−−−+
obj:Ref44329−−−−−−−−−−−>| (数组) |
                       +−−−−−−−−−−−−−−−+   
                       | 0:Ref82445 |−−+
                       +−−−−−−−−−−−−−−+ |
                                        |
                                        | +−−−−−−−−−−−−−−−−−−+
                                        +−−>| (对象) |
                       +−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−−−−−+
已检查对象:Ref12987−−−>| (数组) | | | 编号:1 |
                       +−−−−−−−−−−−−−−+ | | 检查:假|
                       | 0:Ref82445 |−−+ +−−−−−−−−−−−−−−−−+
                       +−−−−−−−−−−−−−−−+

...因此false无论您通过哪个数组查看它,查找它都会给您

obj 是一个对象数组,当你这样做时:

const copiedObj = [...obj];

您创建了一个新数组,但在该数组中您仍将引用来自 obj

发生这种情况是因为您有两个级别:数组 -> 对象,但扩展运算符仅适用于第一级(数组)

这是因为当您copiedObj通过扩展运算符创建 时,您仍在引用最初在内存中创建的对象。

为了解决这个问题,你会得到预期的行为,也是创建对象内所有属性的另一个浅拷贝。

ps 我修改copiedObj[0].checked = false; console.log(obj[0].checked)是因为我认为您试图选择您创建的数组中的第一个元素。

const obj = [{id: 1, checked: true}];
const copiedObj = [Object.assign({}, obj[0])];
copiedObj[0].checked = false;
console.log(obj[0].checked)
//returns true