在JavaScript中实现对对象的“稳定”引用

k10s72fa  于 2023-01-11  发布在  Java
关注(0)|答案(2)|浏览(118)

想象一下下面的对象数组表示单个人。

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中创建一个对对象的“稳定引用”,这样对包含引用的变量的修改就可以应用到它所引用的对象上呢?

8fq7wneg

8fq7wneg1#

没有,
personpeople[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仍然指向旧的对象,那里没有任何改变。

jhkqcmku

jhkqcmku2#

另一方面,我最初的期望是对person的更改会导致对people[i]的更改,因为person === people[i]
对于person/people[i] * 指向的内容 * 的更改,情况也是如此(对象),但对于person * 变量 * 不为真。变量中的值使变量引用对象的变量(或属性)称为 * 对象引用 *。当赋值给person时,您将更改person变量中的内容(在您的情况下,这样它就指向完全不同的对象)。
首先,在内存中存储如下内容(“Ref 12345”值只是为了清楚起见,数字没有任何意义):

+−−−−−−−−−−−−−−−+
                           +−−>|   (object)    |   
                           |   +−−−−−−−−−−−−−−−+   
          +−−−−−−−−−−−−−+  |   | name: "Alice" |   
people−−−>| (array)     |  |   | age: 19       |
          +−−−−−−−−−−−−−+  |   +−−−−−−−−−−−−−−−+
          | 0: Ref13521 |−−+
          | 1: Ref24612 |−−−−−−−−−−−−−−+
          +−−−−−−−−−−−−−+              |
                                       v
                               +−−−−−−−−−−−−−−−+   
person: Ref24612−−−−−−−−−−−−−−>|   (object)    |
                               +−−−−−−−−−−−−−−−+   
                               | name: "Bob"   |
                               | age: 32       |
                               +−−−−−−−−−−−−−−−+

但是当你执行person = ___时,你改变了personvalue(对象person所指向的),使它指向一个完全不同的对象,而people[i]并没有指向这个对象:

+−−−−−−−−−−−−−−−+
                           +−−>|   (object)    |   
                           |   +−−−−−−−−−−−−−−−+   
          +−−−−−−−−−−−−−+  |   | name: "Alice" |   
people−−−>| (array)     |  |   | age: 19       |
          +−−−−−−−−−−−−−+  |   +−−−−−−−−−−−−−−−+
          | 0: Ref13521 |−−+
          | 1: Ref24612 |−−−−−−−−−−−−−−+
          +−−−−−−−−−−−−−+              |
                                       v
                               +−−−−−−−−−−−−−−−+   
                               |   (object)    |
                               +−−−−−−−−−−−−−−−+   
                               | name: "Bob"   |
                               | age: 32       |
                               +−−−−−−−−−−−−−−−+
                     
                               +−−−−−−−−−−−−−−−+
person: Ref74324−−−−−−−−−−−−−−>|   (object)    |
                               +−−−−−−−−−−−−−−−+
                               | name: "Bob"   |
                               | age: 32       |
                               | hair: "brown" |
                               | eyes: "hazel" |
                               +−−−−−−−−−−−−−−−+

是否有可能在JS中创建一个对对象的“稳定引用”...
JavaScript * 中的对象引用是 * 稳定的。这就是 * 变量 * 的工作方式。(不仅在JavaScript中,在许多其他带有对象引用的语言中也是如此,如Java、C#、PHP等)您可以使用const代替letlet person = people[i];这将阻止你改变person中的值,所以你 * 不能 * 将它指向一个不同的对象;这将允许你做你对Alice所做的改变(修改对象),而不是Bob(创建一个新对象并让person指向它)。

相关问题