Home > Net >  Achieving "stable" references to objects in JavaScript
Achieving "stable" references to objects in JavaScript

Time:01-10

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?

CodePudding user response:

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.

CodePudding user response:

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

  • Related