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?
let
andconst
have two broad differences fromvar
:var
before it is declared has the resultundefined
; accessing alet
orconst
before it is declared throwsReferenceError
:It appears from these examples that
let
declarations (andconst
, which works the same way) may not be hoisted, sinceaLet
does not appear to exist before it is assigned a value.That is not the case, however—
let
andconst
are hoisted (likevar
,class
andfunction
), 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:This example shows that
let
is hoisted:Credit: Temporal Dead Zone (TDZ) demystified
Accessing
x
in the inner scope still causes aReferenceError
. Iflet
were not hoisted, it would logouter 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:
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.