I've heard that accessing let
and const
values before they are initialized can cause a ReferenceError
because of something called the temporal dead zone.
What is the temporal dead zone, how does it relate to scope and hoisting, and in what situations is it encountered?
The let and const variables are not accessible before they are initialized with some value, and the phase between the starting of the execution of block in which the let or const variable is declared till that variable is being initialized is called Temporal Dead Zone for the variable.
let and const hoistingVariables declared with let and const are also hoisted but, unlike var , are not initialized with a default value. An exception will be thrown if a variable declared with let or const is read before it is initialized.
In JavaScript, Hoisting is the default behavior of moving all the declarations at the top of the scope before code execution. Basically, it gives us an advantage that no matter where functions and variables are declared, they are moved to the top of their scope regardless of whether their scope is global or local.
Hoisting:let
,const
,var
are all get hoisted process.
(whats mean they go upper and declare in the top of the scope.)
Initialisation:
var
go also through the initial process, and get initial value of undefined
.let
,const
didn't go throw the initial process, so their values are still inaccessible, although they already declared. whats put them in temporal dead zone
So in shortly:
hoisting process:
var
,let
,const
Initialisation process:var
let
and const
have two broad differences from var
:
var
before it is declared has the result undefined
; accessing a let
or const
before it is declared throws ReferenceError
:console.log(aVar); // undefined console.log(aLet); // Causes ReferenceError: Cannot access 'aLet' before initialization var aVar = 1; let aLet = 2;
It appears from these examples that let
declarations (and const
, which works the same way) may not be hoisted, since aLet
does not appear to exist before it is assigned a value.
That is not the case, however—let
and const
are hoisted (like var
, class
and function
), but there is a period between entering scope and being declared where they cannot be accessed. This period is the temporal dead zone (TDZ).
The TDZ ends when aLet
is declared, rather than assigned:
// console.log(aLet) // Would throw ReferenceError let aLet; console.log(aLet); // undefined aLet = 10; console.log(aLet); // 10
This example shows that let
is hoisted:
let x = "outer value"; (function() { // Start TDZ for x. console.log(x); let x = "inner value"; // Declaration ends TDZ for x. }());
Credit: Temporal Dead Zone (TDZ) demystified.
Accessing x
in the inner scope still causes a ReferenceError
. If let
were not hoisted, it would log outer value
.
The TDZ is a good thing because it helps to highlight bugs—accessing a value before it has been declared is rarely intentional.
The TDZ also applies to default function arguments. Arguments are evaluated left to right, and each argument is in the TDZ until it is assigned:
// b is in TDZ until its value is assigned. function testDefaults(a = b, b) { } testDefaults(undefined, 1); // Throws ReferenceError because the evaluation of a reads b before it has been evaluated.
The TDZ is not enabled by default in the babel.js transpiler. Turn on "high compliance" mode to use it in the REPL. Supply the es6.spec.blockScoping
flag to use it with the CLI or as a library.
Recommended further reading: TDZ demystified and ES6 Let, Const and the “Temporal Dead Zone” (TDZ) in Depth.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With