I've been trying to figure out how the temporal dead zone/parsing of let
and const
work. This is what it seemingly boils down to (based on documentation and various responses I received in previous questions [such as this and this], though this goes against some answers given disagreement). Is this summary correct?
At the top of the scope, the JS engine creates a binding (an association of the variable keyword and name, e.g., let foo;
) at the top of the relevant scope, which is considered hoisting the variable, but if you try to access the variable before the location of its declaration, JS throws a ReferenceError
.
Once the JS engine moves down to the declaration (synonymous with "definition"), e.g., let foo;
, the engine initializes it (allocating memory for it and making it accessible). The declaration is self-binding. (Here's the part that doesn't make sense to me: the binding is causing the hoisting at the top, but the engine doesn't initialize until it reaches the declaration, which also has a binding effect.) If there isn't an assignment, the value of the variable is set to undefined
in the case of let
or, if const
is used, a SyntaxError
will be thrown.
For reference here's what the specs say about it:
ECMAScript 2019 Language Specification draft: section 13.3.1, Let and Const Declarations
let and const declarations define variables that are scoped to the running execution context's LexicalEnvironment. The variables are created when their containing Lexical Environment is instantiated but may not be accessed in any way until the variable's LexicalBinding is evaluated. A variable defined by a LexicalBinding with an Initializer is assigned the value of its Initializer's AssignmentExpression when the LexicalBinding is evaluated, not when the variable is created. If a LexicalBinding in a let declaration does not have an Initializer the variable is assigned the value undefined when the LexicalBinding is evaluated.
MDN Web Docs: Let
let bindings are created at the top of the (block) scope containing the declaration, commonly referred to as "hoisting". Unlike variables declared with var, which will start with the value undefined, let variables are not initialized until their definition is evaluated. Accessing the variable before the initialization results in a ReferenceError. The variable is in a "temporal dead zone" from the start of the block until the initialization is processed.