2

This came up at work today. Take the following assignment, commonly used to initialize a variable.

// bill is undeclared
var bill = bill || [];

The value assigned to bill is [].

Why does this fail with a reference error when you omit the var keyword?

// bill is undeclared
bill = bill || [];
jeremysawesome
  • 7,033
  • 5
  • 33
  • 37

1 Answers1

3

You still haven't got an answer so:

var bill = bill || [];

is interpreted exactly as if it had been written:

var bill;
bill = bill || [];

Note that because the reference to bill is after its declaration, there's no exception. It's undefined of course so it'll be set to the empty array.

If another file had been included, then if bill is already a property of the global object then the var does nothing. In particular, the value of the existing global is not affected by the var declaration. The assignment would stick with any non-falsy value.

There are situations where this can happen in a local context. Some build-time code preprocessors may combine separate fragments into a wrapper function. In such cases, the same behavior would happen except that there aren't any global variables involved. Furthermore, if the intention is explicitly to create a global, then you'd probably want

window.bill = window.bill || [];

just to make things unambiguous.

Pointy
  • 405,095
  • 59
  • 585
  • 614
  • Thanks @Pointy. I think what is throwing me off is the concept of implicit globals. Why `bill = 3;` will work without a var... but `bill = bill || 3;` will not. – jeremysawesome Jan 19 '15 at 19:17
  • Well without a `var`, if there's no declared symbol "bill" then the right-hand side will therefore be a reference error. (Hold on, I'm going to look something up to make sure I'm saying it correctly.) – Pointy Jan 19 '15 at 19:20
  • @jeremysawesome when you're not in "strict" mode, the undefined "bill" on the **left** side of the assignment operator is OK. It's the reference on the **right** side that causes the reference error. – Pointy Jan 19 '15 at 19:23
  • 1
    ok. So it seems as if JS doesn't actually create the implicit global until the assignment is executed. Since the assignment itself has a "reference" to something that is undefined then the assignment doesn't succeed and the *implicit global is never created*. I would've thought it would follow the same pattern as the `var` code. Create the variable, then execute the assignment. – jeremysawesome Jan 19 '15 at 19:28
  • would you make reference to the fact that, unlike the explicit variable declaration, an implicit global is not created until the assignment is executed? – jeremysawesome Jan 19 '15 at 19:30
  • @jeremysawesome I'm reading and re-reading the spec trying to figure out where it says that; the spec is really obtuse. – Pointy Jan 19 '15 at 19:34
  • 2
    @jeremysawesome OK if you go through 11.13.1 (Simple Assignment), you'll see that the `GetValue()` call for the right-hand side is called before the call to `PutValue()`. It's inside `PutValue()` that the special case for non-"strict" implicit globals lives. – Pointy Jan 19 '15 at 19:37