1

When instantiating two variables in the same instruction:

var foo = 1,
    bar = foo + 1;

in V8, this yields foo == 1 and bar == 2,

var bar = foo + 1,
    foo = 1;

and this yields foo == 1 and bar == NaN.

Is the order of executed operations guaranteed? Or is it safer to declare foo and bar separately?

var foo = 1;
var bar = foo + 1;

or even

var foo, bar;
foo = 1;
bar = foo + 1;
mingos
  • 23,778
  • 12
  • 70
  • 107
  • 5
    it is guaranteed. what makes you think it wouldn't be? – Daniel A. White Mar 25 '14 at 12:45
  • Some expressions are evaluated right to left. I'd like to rule out the possibility of running into issues when running the code in a different engine than V8. I'm not knowledgeable enough to know for sure. – mingos Mar 25 '14 at 12:54
  • @mingos—"Some expressions are evaluated right to left" no, they aren't, they are always evaluated left to right. In `var foo = 1`, firstly *foo* is created as a local variable before any code is run. Then when evaluating the expression `foo = 1` firstly *foo* is evaluated and found to be a local variable, then the `=` indicates an assignment, then the right hand side is evaluated to see what value will be assigned. – RobG Mar 25 '14 at 13:07
  • @RobG Have a look at this answer: http://stackoverflow.com/a/5944603/244727 - it suggests otherwise (though the comments underneath it do not)... – mingos Mar 25 '14 at 13:28
  • @mingos—if the post is accurate, the (unstated) version of Chrome used doesn't [conform to the spec](http://ecma-international.org/ecma-262/5.1/#sec-11.8.1), which says that when evaluating `<` and `>` the left hand side is evaluated first. Chrome 33 on Mac OS behaves the same as Safari and Firefox and goes left to right for both cases. That post is from 3 years ago though, so maybe Chrome is compliant *now*. :-) – RobG Mar 25 '14 at 13:47
  • @RobG I failed to confirm what the post states as well. I must have been wrong about the order then. Still, it's good to have a confirmation on that :). – mingos Mar 25 '14 at 21:33

3 Answers3

3

As you have noted correctly, the variable declaration expressions will be evaluated from left to right. The left hand side of the assignment will be evaluated first, right hand side of the assignment expression will be evaluated next, and then assigned.

In the second case, you got NaN, because of variable hoisting. When JavaScript sees

bar = foo + 1,

it will know that foo is defined in the current context, but not yet assigned a value. So, by default, it uses undefined for foo.

console.log(undefined + 1);
# NaN

That is why NaN is assigned to bar.

According to the ECMA 5.1 Standard Docs' Variable Statement section, variable declaration will be evaluated like this

VariableStatement:
    var VariableDeclarationList ;

VariableDeclarationList :
    VariableDeclaration
    VariableDeclarationList , VariableDeclaration*

Here, the production will be evaluated like this

The production VariableDeclarationList : VariableDeclarationList , VariableDeclaration is evaluated as follows:

  1. Evaluate VariableDeclarationList.
  2. Evaluate VariableDeclaration.

So, the left most assignment expressions should be evaluated first, and at the last only, the right most one. So, the behavior you see, is the expected behavior.

thefourtheye
  • 233,700
  • 52
  • 457
  • 497
  • I understand why `NaN` was assigned - this is exactly what I was hoping to happen, really. I'm asking whether this behaviour is guaranteed to happen always - which luckily seems to be the case :). – mingos Mar 25 '14 at 12:51
  • @RobG Just checked the spec and you are correct. Thanks :) Updated the answer. – thefourtheye Mar 25 '14 at 13:21
2

When declaring and initializing variables in the same instruction, javascript executes the actions in exactly the order you would expect.

For example,

var foo = 1,
    bar = foo + 1;

is perfectly valid, and will never produce errors. On the other hand

var bar = foo + 1,
    foo = 1;

will produce bar === NaN, just like you stated, because the first thing that will happen is bar will be initialized as foo + 1, where foo is technically undefined.

tl;dr Yes.

  • In the second case, at the moment of initialising `bar`, `foo` is actually `undefined`, not `NaN`. – mingos Mar 25 '14 at 12:56
1

The difference between

// Case 1 var foo = 1, bar = foo + 1;

and

Case 2 var bar = foo + 1, foo = 1;

is that in the first case foo is already defined as 1 so your operation is 1+1 In the second case the moment you define bar, foo is still undefined. Although it is already declared.

In JS all declaration will happen before the program runs. So even if all your var statements are at the bottom of you code it would work. See here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var#var_hoisting

Taner Topal
  • 921
  • 8
  • 14