Reputation: 5692
Consider the following statements:
var foo = {n: 1};
foo.bar = foo = {n: 2};
Can you explain why foo.bar
is undefined
instead of being foo
?
Upvotes: 6
Views: 718
Reputation: 214969
When executing the assignment operator, JS evaluates the left part first. So this
foo.bar = foo = {n: 2};
is interpreted as
evaluate foo.bar
. This returns a reference {base: Object {n:1}, property:bar}
.
then evaluate the second assignment:
2.1 eval foo
. This returns a reference {base:<scope>, property:foo}
2.2. eval {n:2}
. This creates a new object.
2.3 put value: <scope>.foo = {n:2}
2.4 return {n:2}
put value to the first reference: {n:1}.bar = {n:2}
. This runs fine, but the old object {n:1}
is not accessible anymore, since <scope>.foo
already refers to the new object
Details: http://ecma-international.org/ecma-262/5.1/#sec-11.13.1
If you make a copy of foo
before, you'll see that the leftmost =
actually modifies the old object:
var foo = {n:1};
var oldFoo = foo;
foo.bar = foo = {n: 2};
document.write(JSON.stringify(foo) + "<br>")
document.write(JSON.stringify(oldFoo) + "<br>")
Upvotes: 12
Reputation: 95022
There are two objects at play here. One will have a bar property, the other wont. To show this, i'll store the original object in another variable for comparison.
var foo = {n: 1};
var orig = foo;
foo.bar = foo = {n: 2};
console.log(foo, orig); // {n:2}, {n:1, bar: {n:2}}
Until the foo.bar
line is done executing, foo
still contains the original object, so the bar property of the original object will be set to the new object.
Upvotes: 1
Reputation: 190943
So by the time the assignment for foo.bar
happens, the reference is "filled in" for foo
. which makes it the original object.
Let's expand your code a bit to make it more clear.
var foo1, foo2;
foo1 = foo2 = {n:1};
foo1 === foo2; // true
foo1.bar = foo1 = {n:2}
foo1.bar === foo2; // false
foo1 === foo2; // false
Upvotes: 2
Reputation: 36592
You changed the object to which foo
refers. There is no bar
in {n: 2}
. What did you expect?
Upvotes: 0