Why does var APP = APP || {};
work fine, but const APP = APP || {};
not? Or let APP = APP || {}
for that matter.
Uncaught ReferenceError: APP is not defined
As this only has to do with the evaluation of APP and not anything of what it is set to.
Why does var APP = APP || {};
work fine, but const APP = APP || {};
not? Or let APP = APP || {}
for that matter.
Uncaught ReferenceError: APP is not defined
As this only has to do with the evaluation of APP and not anything of what it is set to.
Share Improve this question asked Oct 27, 2017 at 19:32 Afs35mmAfs35mm 6493 gold badges11 silver badges25 bronze badges 5- 2 Well const can only be declared once so using that pattern seems wrong. – epascarello Commented Oct 27, 2017 at 19:33
- 1 Maybe stackoverflow./questions/31219420/… – epascarello Commented Oct 27, 2017 at 19:36
- What do you mean by "work fine"? What is this code supposed to be doing? – melpomene Commented Oct 27, 2017 at 19:39
-
2
||
is JavaScript's logical OR – it can be used to coalesce falsey values, but it's not a null-coalescing operator. – Mulan Commented Oct 27, 2017 at 19:42 -
It's most likely because with
var
it's actuallyvar App=undefined;APP = APP || {}
due to var hoisting. Do the same withlet
and it would work too. – Keith Commented Oct 27, 2017 at 19:52
2 Answers
Reset to default 10Why does
var APP = APP || {};
work fine, butconst APP = APP || {};
not?
Lets clarify how these statements are evaluated. Before any code is executed, the runtime finds all variable declarations and creates an entry for each in the current scope. Some time later when APP = APP || {}
is executed, the value of APP
is read before it was ever assigned value.
It "works" with var
, because var
declarations are implicitly initialized with the value undefined
. Therefore accessing the variable before a value is assigned to it returns undefined
.
const
and let
declarations however are left uninitialized. You cannot access them before they have been assigned the value from their initial declaration. This is also known as temporal dead zone or TDZ for short.
Here is a simplified example:
console.log(foo); // undefined
var foo = 42;
console.log(foo); // 42
vs
console.log(foo); // ReferenceError because of TDZ
let foo = 42;
console.log(foo); // 42 in theory, but this line is never executed due to the error above
From MDN:
In ECMAScript 2015, let bindings are not subject to Variable Hoisting, which means that let declarations do not move to the top of the current execution context. Referencing the variable in the block before the initialization results in a ReferenceError (contrary to a variable declared with var, which will just have the undefined value). The variable is in a "temporal dead zone" from the start of the block until the initialization is processed.
The same applies for const
:
All the considerations about the "temporal dead zone" apply to both let and const.
In other words, the reason this works:
var APP = APP || {};
is because of variable-hoisting which translates the above to:
var APP; // <-- declares APP
APP = APP || {}; // <-- initializes APP
and since variable-hoisting does not apply to either let
or const
:
const APP = APP || {}; // <-- Fails because APP is not yet initialized.
let APP = APP || {}; // <-- Fails for the same reason.
Finally, for the record (as rightly pointed out by naomik), the ||
operator is not a null-coalescing operator but rather a short-circuit OR operator.
The confusion over this is likely because of statements like this:
var n = n || '';
For the above statement, there are two things to bear in mind with these.
n
is notnull
... it isundefined
(which is different from null).Because of variable-hoisting, that statement is the equivalent of:
var n; // n has the value of undefined n = n || ''; // the parison is now: undefined || '';
and since undefined
is a "falsy" value, the short-circuit OR operator returns the second value.
This behavior holds true for null
as well, because null
is also "falsy".