【问题标题】:Achieving "stable" references to objects in JavaScript在 JavaScript 中实现对对象的“稳定”引用
【发布时间】:2023-01-10 21:58:15
【问题描述】:

想象以下代表个人的对象数组。

let people = [

    {
        name: 'Alice',
        age: 19
    },
    {
        name: 'Bob',
        age: 32
    },
]

您需要遍历每个对象,并将人物的头发和眼睛颜色添加到他们的对象中。幸运的是,他们都有棕色的头发和淡褐色的眼睛,因此您的任务变得简单了。出于某种原因,您决定使用属性访问器对于爱丽丝和一个解构赋值对于鲍勃。最后,您记录结果。

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));

但是,新信息出现在爱丽丝的对象中,但不在鲍勃的对象中!

{ 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]。因此,这里的修复是将 person = { ...person, ...additionalInfo } 换成 people[i] = { ...person, ...additionalInfo } 有点令人惊讶。

为什么会这样?是否有可能在 JS 中创建一个对象的“稳定引用”,以便对包含引用的变量的更改应用于它所引用的对象?

【问题讨论】:

  • person = ... 表示您正在为局部变量person 分配一个新值。这不会影响people[i]
  • “......以及 Bob 的解构任务......”那不是解构赋值。恰恰相反,它是结构化使用扩展语法赋值(创建对象)。
  • 你关于“稳定”参考的问题的答案是否定的。您不能将对象属性或变量作为另一个变量的别名。你可以使用像 C++ 这样的语言,因为你可以使变量成为显式引用类型,但你不能使用 JavaScript。
  • 问题不在于解构赋值,问题在于您忘记了语法 {}new Object() 的简写。您正在创建一个新对象,并将其分配给变量person。所以现在 person 指向那个新对象而不是 people[i]
  • @Pointy 实际上,即使在 C++ 中,当他忘记执行类似 a = new X() 的操作不会更改 a 先前指向的内容,而是将地址分配给一个新对象时,他也会遇到这样的代码问题.

标签: javascript javascript-objects


【解决方案1】:

不,

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 仍然指向旧对象并且那里没有任何变化。

【讨论】:

    【解决方案2】:

    另一方面,我最初的预期是对person 的更改会导致对people[i] 的更改,因为person === people[i]

    对于person/people[i]的更改也是如此指向(对象),但不适用于 person变量.变量(或属性)中使该变量引用对象的值称为对象引用.当您分配给 person 时,您正在更改 person 变量中的内容(在您的情况下,它指向完全不同的对象)。

    您从内存中的类似内容开始(“Ref12345”值只是为了清楚起见,数字并不代表任何内容):

    +——————————————————————+
                               +−−>| (对象) |
                               | +——————————————————————+
              +–––––––––––+ | |名称:“爱丽丝” |
    人们---->| (数组) | | |年龄:19 |
              +–––––––––––+ | +——————————————————————+
              | 0: Ref13521 |——+
              | 1: Ref24612 |---------------------------------+
              +–––––––––––+ |
                                           v
                                   +——————————————————————+
    人:Ref24612-------------------------->| (对象) |
                                   +——————————————————————+
                                   |名称:“鲍勃” |
                                   |年龄:32 |
                                   +——————————————————————+

    但是当你做person = ___时,你改变了价值personperson 指向的对象),使其指向 people[i] 未指向的完全不同的对象:

    +---------------------------------------+
                               +−−>| (对象) |
                               | +---------------------------------------+
              +–––––––––––+ | |名称:“爱丽丝” |
    人们---->| (数组) | | |年龄:19 |
              +–––––––––––+ | +---------------------------------------+
              | 0: Ref13521 |——+
              | 1: Ref24612 |---------------------------------+
              +–––––––––––+ |
                                           v
                                   +---------------------------------------+
                                   | (对象) |
                                   +---------------------------------------+
                                   |名称:“鲍勃” |
                                   |年龄:32 |
                                   +---------------------------------------+
                         
                                   +---------------------------------------+
    人:Ref74324-------------------------->| (对象) |
                                   +---------------------------------------+
                                   |名称:“鲍勃” |
                                   |年龄:32 |
                                   |头发:“棕色” |
                                   |眼睛:“淡褐色”|
                                   +---------------------------------------+

    甚至有可能在 JS 中创建对对象的“稳定引用”......

    JavaScript 中的对象引用稳定的。就是这样变量工作。 (不仅在 JavaScript 中,而且在许多其他具有对象引用的语言中,例如 Java、C#、PHP 等)您可以使用 const 代替 let 而不是 letlet person = people[i]; 那会防止你改变person中的值,所以你不能将其指向不同的对象。这样您就可以进行对 Alice 所做的更改(修改对象),但不能对 Bob 进行更改(创建一个新对象并让 person 指向它)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-28
      • 2016-04-17
      • 1970-01-01
      相关资源
      最近更新 更多