6
 var foo = {};
 foo.c = foo = {};
 console.log(foo.c);

why the result is undefined? i thought it is supposed to be '[object Object]'

user1039304
  • 365
  • 5
  • 10

2 Answers2

11

Strange things are happening here in the assignments:

foo.c = (foo = {})

The reference to foo.c is resolved first and points to the old foo object, before the inner expression is evaluated where foo is re-assigned with the {} emtpy object literal. So your code is equivalent to

var foo1 = {};
var foo2 = {};
foo1.c = foo2;
console.log(foo2.c) // obviously undefined now

You can also try

var foo = {}, old = foo;
foo.c = foo = {};
console.log(old, foo, old.c===foo); // {c:{}}, {}, true
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • But isn't the order of evaluation right to left in `foo.c = foo = {};` ? i.e. `foo` becomes `{}` first, and then that result is assigned to `foo.c` ? – techfoobar Feb 24 '14 at 05:12
  • 1
    @techfoobar: Because it's out-to-in, and left-to-right. Only operator precedence is right-to-left. – Bergi Feb 24 '14 at 05:13
  • 4
    @techfoobar - According to [the spec (section 11.13.1)](http://www.ecma-international.org/ecma-262/5.1/#sec-11.13.1), the left side of the assignment is resolved before the right side is evaluated. Thus `foo.c` is resolved as Bergi describes before the right side (which involves another assignment) is evaluated. – Ted Hopp Feb 24 '14 at 05:15
  • Maybe I'm weird, but diving into the specification and figuring these things out is fun :) Good job! – Felix Kling Feb 24 '14 at 05:20
0

JavaScript engine splits such assignment:

a = b = c = 1;

As follow:

a = 1;
b = 1;
c = 1;

And not as:

c = 1;
b = c;
a = b;

There is a slightly but important difference – mostly, it involves getters, please check Multiple variable assignments in one row for further details – and that's mostly why your code doesn't behave like expected, because the initial expectations are based on false assumptions.

Community
  • 1
  • 1
ZER0
  • 24,846
  • 5
  • 51
  • 54
  • 1
    Actually that is incorrect. The statement is evaluated as `a = (b = (c = 1));`. So the assignment `c = 1` takes place first, and it's result (`1`) is assigned to `b`, etc. I'm thinking about a good way to demonstrate that. – Felix Kling Feb 24 '14 at 05:40
  • That's no true @FelixKling. Please, check my answer linked above, you will find a code that demonstrate how the JavaScript engine works in that specific case. – ZER0 Feb 24 '14 at 05:43
  • The link actually confirms my statement. Did you check the order of the variables? Don't understand why you are claiming something else now :) To be clear: I'm not talking about the values that are assigned, I'm talking about the *order* of the assignment. And that alone does not explain the output the OP gets. – Felix Kling Feb 24 '14 at 05:45
  • I'm not claiming something else. :) Maybe there is a misunderstanding, I'm just saying that `a = b = 1` is not equals to `b = 1, a = b` but rather to `a = 1, b = 1`. It's a well known behavior of JavaScript – I'm working on spidermonkey. – ZER0 Feb 24 '14 at 05:48
  • Yes, I understand that. But in this answer, you claim that `a` gets a value first, then `b` and then `c`, while it's the other way round, just like you wrote in your other answer. So, `a = b = 1` is `b = 1, a = 1`, not `a = 1, b = 1`. The order is very important here. Because it means that `foo.c = foo = {};` is equivalent to `foo = {}; foo.c = {}`, which doesn't explain why `console.log(foo.c)` shows `undefined`. – Felix Kling Feb 24 '14 at 05:49
  • In the example I made here it doesn't matter the order of the first assignment, where it matters if you start from the false assumption that `b` gets `c`. In fact the second part the order starts from the last variable. `foo.c` shows undefined exactly for that behavior: you do not assign {} to `foo` and then `foo.c` to `foo`: that's the false assumption. – ZER0 Feb 24 '14 at 05:52
  • Uh? I don't get your last point. You are saying that `foo.c = foo = {}` is `foo = {}; foo.c = {};`, right? So how does this explain the output? And you are right, in your example, the order does not matter, but in the OP's example, the order *does* matter. – Felix Kling Feb 24 '14 at 05:55
  • I'm saying that `var foo = {}; foo.c = foo = {}` is more like `var foo; foo = {}; foo.c = {}; foo = {}`. – ZER0 Feb 24 '14 at 06:03
  • So we are back to my first comment. You are claiming that `foo.c` is assigned first, and then `foo`. Yet in your other question, you proof exactly the opposite. – Felix Kling Feb 24 '14 at 06:04
  • Maybe there is a misunderstanding as I said, and I'm sorry I do not want to continue to discuss in the comment: in your first comment you said " So the assignment c = 1 takes place first, and it's result (1) is assigned to b" and this, expressed in this form, I think is not correct or at least misleading. That's all. – ZER0 Feb 24 '14 at 06:08
  • OK. Your answer still doesn't explain the problem here though. Check Bergi's answer. Have a good day! – Felix Kling Feb 24 '14 at 06:11