JavaScript code trick: What's the value of foo.x

I found this problem in a GitHub front-end interview questions collection:

var foo = {n: 1};
var bar = foo;
foo.x = foo = {n: 2};

Question: What is the value of foo.x?

The answer is undefined.

I've done some research and what I understand this problem is (correct me if I'm wrong):

  • var foo = {n: 1}; declares an object foo which has property n equal to 1.
  • var bar = foo; declares an object bar which refers to the same object as foo.
  • foo.x = foo = {n: 2}; which I believe is equal to foo.x = (foo = {n: 2});
  • And then I got foo.x equals to undefined. However, the value of bar.x is the object {n:2}.

If bar and foo refer to same object, why did bar.x get a value while foo.x is undefined? What is really happening in foo.x = foo = {n: 2};?


Solution 1:

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

determines that foo.x refers to a property x of the {n: 1} object, assigns {n: 2} to foo, and assigns the new value of foo{n: 2} – to the property x of the {n: 1} object.

The important thing is that the foo that foo.x refers to is determined before foo changes.

See section 11.13.1 of the ES5 spec:

  1. Let lref be the result of evaluating LeftHandSideExpression.

  2. Let rref be the result of evaluating AssignmentExpression.

The assignment operator associates right to left, so you get:

foo.x = (foo = {n: 2})

The left hand side is evaluated before the right hand side.

Solution 2:

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

Here foo refers to {n:1} object before assignment i.e. before the statement is executed.

The statement can be re-written as foo.x = (foo = {n:2});

In object terms the above statement can be re-written as {n:1}.x = ( {n:1} = {n:2} );

Since assignment happens from right to left only. So here we just have to keep a check that foo is referring to which object before execution starts.

On solving the R.H.S: foo = {n:2}; Now foo is referring to {n:2};

Coming back on the problem we are left with:

foo.x = foo;

Now foo.x on L.H.S is still {n:1}.x whereas foo on R.H.S is {n:2}.

So after this statement gets executed {n:1} will become { n:1, x:{n:2} } with bar still referring to it. Where as foo will now be referring to {n:2}.

So on execution foo.x gives undefined as there is only 1 value in foo which is {n:2}.

But if you will try executing bar.x it will give {n:2}. Or if you will just execute bar the result will be

Object {n: 1, x: Object}

Solution 3:

As I understand expression :

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

just exactly the same as:

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

And after this it's became obvious that:

 bar=={n: 1, x: {n:2}};
 foo=={n:2};
 foo.x==undefined

Solution 4:

I thought I'd add another, what I found to be, helpful way of thinking about this.

Those last variable assignments are equivalent to writing bar.x = foo = {n:2};, because those variables are just references to the same thing in memory.

In other words, foo and bar are, at first, both referencing the same object, {n:1}. When you use foo.x =, you are accessing {n:1} and adding the x property to it. This could be done with either bar or foo because they both point to that same object in memory! It makes no difference.

Then when you complete that line, foo.x = foo = {n:2}, you are creating another, brand new, object in memory via object literal syntax and setting foo to point to that object, {n:2}, instead of what is now {n:1, x: {n: 2}. This doesn't affect what foo pointed to when you added the x property to it, though.

This is pretty confusing, but I think makes sense you think about the fact that variables are just pointers to places/objects in memory, and that object literal syntax isn't changing the previously existing object (even though they look similar). It's creating a brand new one.

The beginning of accepted answer to this question may be helpful as well.