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 topeople[i]
becauseperson === 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).