Why Does let Appear Not to Be Hoisted? Unraveling JavaScript’s Variable Lifecycle
This article chronicles the author’s two‑month journey of understanding JavaScript’s let declaration, exploring its block scope, temporal dead zone, per‑iteration bindings, and the nuanced differences from var and function hoisting, while debunking common misconceptions with code examples and spec references.
1 Preface
I spent two months piecing together my understanding of let, writing this article to help others who are self‑studying JavaScript.
2 Getting to Know let
From MDN I learned three key points:
let creates block‑scoped variables;
let cannot redeclare an existing variable;
let has a temporal dead zone and is not hoisted.
3 First Doubt
When using a
forloop, the following code with
varprints five times the number 5:
<code>// code snippet 1
var liList = document.querySelectorAll('li');
for (var i = 0; i < liList.length; i++) {
liList[i].onclick = function() { console.log(i); };
}</code>Replacing
var iwith
let iprints 0, 1, 2, 3, 4 as expected:
<code>// code snippet 2
var liList = document.querySelectorAll('li');
for (let i = 0; i < liList.length; i++) {
liList[i].onclick = function() { console.log(i); };
}</code>The original reasoning fails because only one
iis declared, so after the loop finishes its value becomes 5.
MDN’s example avoids this by introducing a hidden
jthat captures the current
ivalue.
4 Second Doubt
A StackOverflow question asked whether let is hoisted. One high‑voted answer claimed all declarations are hoisted, citing code that appears to access
xbefore its declaration.
<code>x = "global";
(function() {
x; // not "global"
var/let/... x;
})();
{
x; // not "global"
let/const/... x;
}</code>Further research revealed contradictory MDN edits and the ES spec’s mention of “var/let hoisting”.
TC39 member Rick Waldron clarified that the term “hoisting” is non‑normative for let/const: they do not hoist like var or function declarations.
You're misunderstanding the intention of that (non‑normative) Note. let and const do not hoist as var and function decls do.
5 The Story Continues
Understanding hoisting requires distinguishing creation, initialization, and assignment of variables.
var creates the variable and initializes it to
undefinedbefore code runs, then assigns values during execution.
function declarations are created, initialized, and assigned before execution.
let creates the binding during the creation phase, but initialization occurs when the declaration is evaluated; before that the variable is in the temporal dead zone.
<code>{
let x = 1;
x = 2;
}</code>This explains why accessing
xbefore its
letdeclaration throws a ReferenceError.
Similarly,
consthas creation and initialization only, with no later assignment.
The following diagram (image) summarizes the lifecycle of var, let, const, and function declarations.
5 Is It Over?
When
let x = xfails, the variable remains in the created state forever, never initialized, and stays in the temporal dead zone, effectively halting further execution.
These observations illustrate the subtle but important differences in JavaScript’s variable handling.
Tencent IMWeb Frontend Team
IMWeb Frontend Community gathering frontend development enthusiasts. Follow us for refined live courses by top experts, cutting‑edge technical posts, and to sharpen your frontend skills.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.