想象一下下面的对象数组表示单个人。
let people = [
{
name: 'Alice',
age: 19
},
{
name: 'Bob',
age: 32
},
]
你需要循环遍历每个对象,并将这个人的头发和眼睛的颜色添加到他们的对象中。幸运的是,你的任务被简化了,因为他们都有棕色的头发和淡褐色的眼睛。出于某种原因,你决定对Alice使用属性访问器,对Bob使用解构赋值。最后,你记录结果。
for (let i = 0; i < people.length; i++) {
let person = people[i];
if (person.name === 'Alice') {
person.hair = 'brown';
person.eyes = 'hazel';
}
else if (person.name === 'Bob') {
let additionalInfo = {
hair: 'brown',
eye: 'hazel'
}
person = { ...person, ...additionalInfo }
}
}
people.forEach(person => console.log(person));
然而,新信息出现在Alice的对象中,而不在Bob的对象中!
{ name: 'Alice', age: 19, hair: 'brown', eyes: 'hazel' }
{ name: 'Bob', age: 32 }
现在,我明白为什么Alice的对象会更新了:person.hair = 'brown'
被当作people[i].hair = 'brown'
来处理,因为person === people[i]
。
在这个例子中,我多少但不是完全理解为什么Bob不能这样做,一方面,我们将person变量重新分配给people[i]
以外的变量,从而丢失了引用,person
在那次迭代后丢失,Bob的对象没有任何改变。
另一方面,我最初的预期是,对person
的更改会导致对people[i]
的更改,因为person === people[i]
。因此,这里的修复是用people[i] = { ...person, ...additionalInfo }
替换person = { ...person, ...additionalInfo }
,这有点令人惊讶。
为什么会这样呢?有没有可能在JS中创建一个对对象的“稳定引用”,这样对包含引用的变量的修改就可以应用到它所引用的对象上呢?
2条答案
按热度按时间8fq7wneg1#
没有,
person
和people[i]
是对同一事物的两个引用。当你指定一个引用时,它会更新它所指向的内容
例如
let a = {x:1}
如果你这样做
b = a
b
不是对象{x:1}
..它只是指向该对象当你说
b.x = 3
的时候。那是因为你说change the x property on the object b is pointing to
但当你这么做时
b = {y:2}
现在你说
b
应该指向这个新的对象..a
仍然指向旧的对象,那里没有任何改变。jhkqcmku2#
另一方面,我最初的期望是对
person
的更改会导致对people[i]
的更改,因为person === people[i]
。对于
person
/people[i]
* 指向的内容 * 的更改,情况也是如此(对象),但对于person
* 变量 * 不为真。变量中的值使变量引用对象的变量(或属性)称为 * 对象引用 *。当赋值给person
时,您将更改person
变量中的内容(在您的情况下,这样它就指向完全不同的对象)。首先,在内存中存储如下内容(“Ref 12345”值只是为了清楚起见,数字没有任何意义):
但是当你执行
person = ___
时,你改变了person
的 value(对象person
所指向的),使它指向一个完全不同的对象,而people[i]
并没有指向这个对象:是否有可能在JS中创建一个对对象的“稳定引用”...
JavaScript * 中的对象引用是 * 稳定的。这就是 * 变量 * 的工作方式。(不仅在JavaScript中,在许多其他带有对象引用的语言中也是如此,如Java、C#、PHP等)您可以使用
const
代替let
:let person = people[i];
这将阻止你改变person
中的值,所以你 * 不能 * 将它指向一个不同的对象;这将允许你做你对Alice所做的改变(修改对象),而不是Bob(创建一个新对象并让person
指向它)。