Antoine
Antoine

Reputation: 5692

Chained assignment and circular reference in JavaScript

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

Answers (4)

georg
georg

Reputation: 214969

When executing the assignment operator, JS evaluates the left part first. So this

foo.bar = foo = {n: 2};

is interpreted as

  1. evaluate foo.bar. This returns a reference {base: Object {n:1}, property:bar}.

  2. 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}

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

Kevin B
Kevin B

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

Daniel A. White
Daniel A. White

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

Evan Davis
Evan Davis

Reputation: 36592

You changed the object to which foo refers. There is no bar in {n: 2}. What did you expect?

Upvotes: 0

Related Questions