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

7

60

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};?

Emetine answered 2/9, 2015 at 0:16 Comment(1)
And questions like that on an interview are horrible...Kimberykimble
M
60
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.

Manifestative answered 2/9, 2015 at 0:23 Comment(5)
Is the reference resolution order mandated by some standard or is it just how particular implementation does it?Spinks
@soulcheck: It is mandated by the standard. Finding important parts now. (It’s also somewhat mandated by common sense – consider (x = {}).y = x)Manifestative
@Spinks Thanks. And so do you mean that foo is {n:2} now after assignment, but foo.x belong to the old 'foo = {n:1}' object which is not exist anymore because foo has been changed to {n:2} And thus foo.x fail to be assigned the value but bar.x got the value because bar always exist and never been changed? Oh my...Emetine
@AndyHu: foo.x refers to the x of the old foo. bar also refers to the old foo. x does not exist on the new foo.Manifestative
@minitech Ok I got it. Thanks.Emetine
A
25
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}
Arnettaarnette answered 18/7, 2016 at 14:9 Comment(0)
G
12

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
Granite answered 19/7, 2018 at 7:59 Comment(0)
B
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.

Blanca answered 2/6, 2017 at 22:51 Comment(1)
This is helpful! The key for me was realizing that bar becomes {n: 1, x: {n: 2}} and foo becomes {n: 2}. That is why the problem introduces the bar variable.Lh
G
4

It is a matter of understanding that object variables are merely references to the objects in JavaScript and not objects themselves.

var foo = {n: 1} -> foo refers to the real object {n: 1} var bar = foo -> bar is now also a reference to the real object {n: 1}

The tricky part is of course the 3rd line: foo.x = foo = {n: 2}

This is equivalent to: (reference to {n: 1}).x = (foo = {n: 2}) -> after this line is completely evaluated, foo becomes a reference to the new object {n: 2}; however, since foo refers to the original object {n: 1} prior to the evaluation of the line, the original object {n: 1} becomes {n: 1, x: [reference to]{n: 2}} after the line is evaluated, and the modified object will be accessible through the reference bar. If there was no reference bar, the original object would be destroyed

Galingale answered 15/10, 2017 at 3:20 Comment(0)
C
0

An easy way to understand this is using references.

When var foo = {n: 1}; executes, let's say memory gets allocated to this object at location A. So, foo is currently pointing to A.

When var bar = foo; executes and bar refers to the same location A.

When foo.x = foo = {n: 2}; executes, firstly referencing will take place and then the assignment will happen from right to left.

One can visualize it like this:

Another memory location will be created for {n: 2}, say 'B'

(object at A).x = foo = (object at B);

Step1: the assignment will start from right to left, so foo will point to B location.

Step 2: the object at A (i.e. {n: 1}) will have another property x with value foo ({n: 2}); bar still points to A memory location, so it will have this value. enter image description here

Cockscomb answered 29/1 at 22:0 Comment(0)
M
-1

i think in Javascript you cant assign a value to a property which doesn't exist if the object isn't empty. so in this case foo object has a property and value pair which is {n:1} so since it isn't empty and it doesn't have a x property ,you cant assign but since you assign bar object a value which is foo object ,it will have the value whatever the foo is

Marcellemarcellina answered 6/5, 2019 at 21:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.