1

Imagine the following array of objects representing individual people.

let people = [

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

You are asked to loop over each object and to add the person's hair and eye color to their object. Fortunately, your task is simplified by the fact that they both have brown hair and hazel eyes. For some reason, you decide to use a property accessor for Alice and a destructuring assignment for Bob. Finally, you log the result.

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

However, the new information is present in Alice's object but not in Bob's!

{ name: 'Alice', age: 19, hair: 'brown', eyes: 'hazel' }
{ name: 'Bob', age: 32 }

Now, I understand why Alice's object gets updated: person.hair = 'brown' get treated as people[i].hair = 'brown' because person === people[i].

I somewhat but not fully understand why this doesn't work with Bob in this example. On one hand, we are reassigning the person variable to something other than people[i], thereby losing the reference, and person is lost after that iteration with no changes made to Bob's object.

On the other hand, my initial expectation was that changes to person would result in changes to people[i] because person === people[i]. Hence it is a little surprising the fix here is to swap out person = { ...person, ...additionalInfo } with people[i] = { ...person, ...additionalInfo }.

Why is this the case? Is it even possible to create a "stable reference" to an object in JS such that changes to the variable containing the reference are applied to the object it is referring to?

7
  • 4
    person = ... means your are assigning a new value to the local variable person. That will not affect people[i]. Commented Jan 10, 2023 at 13:38
  • 1
    "...and a destructuring assignment for Bob..." That isn't destructuring assignment. Quite the opposite, it's structuring assignment (creating an object) using spread syntax. Commented Jan 10, 2023 at 13:40
  • 2
    And the answer to your question about "stable" references is no. You cannot alias an object property or variable with another variable. You can in a language like C++ because you can make a variable an explicit reference type, but you can't in JavaScript. Commented Jan 10, 2023 at 13:40
  • The problem is not the destructuring assignment, the problem is that you forgot that the syntax {} is shorthand for new Object(). You are creating a new object, and assigning it to the variable person. So now person is pointing to that new object instead of people[i] Commented Jan 10, 2023 at 13:43
  • 1
    @Pointy Actually, even in C++ he'll have problems with code like this when he forgets that doing something like a = new X() does not change the content of what a previously pointed to but instead assigns the address to a new object to it. Commented Jan 10, 2023 at 13:46

2 Answers 2

2

no,

person and people[i] are two reference to same thing..

when you assign to a reference it updates what it is pointing to

eg.

let a = {x:1}

if you do

b = a

b is not the object {x:1} .. it merely points to that object

when you do b.x = 3 . that works because you say change the x property on the object b is pointing to

but when you do

b = {y:2}

now you are saying b should point to this new object.. a still points to the older object and nothing changes there.

Sign up to request clarification or add additional context in comments.

Comments

1

On the other hand, my initial expectation was that changes to person would result in changes to people[i] because person === people[i].

That's true for changes to what person/people[i] point to (the object), but not true for person the variable. The value in a variable (or property) that makes that variable refer to an object is called an object reference. When you assign to person, you're changing what's in the person variable (in your case, so that it points to a different object entirely).

You start out with something like this in memory (the "Ref12345" values are just for clarity, the numbers don't mean anything):

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

but then when you do person = ___, you change the value of person (which object person points to), making it point to a whole different object that people[i] doesn't point to:

                               +−−−−−−−−−−−−−−−+
                           +−−>|   (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" |
                               +−−−−−−−−−−−−−−−+

Is it even possible to create a "stable reference" to an object in JS...

Object references in JavaScript are stable. This is just how variables work. (Not only in JavaScript, but also in many other languages with object references, such as Java, C#, PHP, ...) You could use a const for person instead of let: let person = people[i]; That would prevent you changing the value in person, so you couldn't point it at a different object. That would let you do the changes you did for Alice (modifying the object) but not Bob (creating a new object and having person point to it).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.