Hoisting and the TDZ
Let's go back to the apartment with rooms. Before anyone walks into the apartment, JavaScript goes through it and sets out, in advance, a labeled box for every variable declared there. That is why a variable can exist before the line with its declaration runs.
A var variable can be read above the line where it is declared, and the program does not stop. The first line of this function prints undefined, even though total is declared below:
function order() {
console.log(total); // undefined
var total = 10;
console.log(total); // 10
}
order();Let's walk through the call order() step by step:
- Even before the function's first line, the variable
totalalready exists and holdsundefined. - The first
console.log(total)printsundefined. - The line
var total = 10puts the number10intototal. - The second
console.log(total)prints10.
If the third line says let total = 10, the same function stops with an error. The difference lies in what JavaScript does with declarations before it runs the first line.
What gets hoisted
In chapter 5 you saw that a function declaration can be called above its text: that is hoisting. In fact JavaScript creates every variable declared in a function or file in advance, not only functions. Before calling a function it looks through the function's body, and before running a file, through the whole file.
Here the box picture and the word "hoisting" itself are inaccurate: no line of the program actually moves anywhere. Declarations stay where they are in the text; JavaScript only processes them before the other lines.
What exactly is ready in advance depends on the kind of declaration.
Function declarations
A function declaration is hoisted whole, together with its body. So a function can be called above its text.
var variables
A var variable is hoisted without a value: from the function's first line it already exists and holds undefined. It gets the value 10 only when the line var total = 10 runs.
The declaration is hoisted, while the assignment stays where it is. A var from an if branch or a loop is hoisted to the start of the whole function, since var ignores blocks.
The temporal dead zone
let and const variables are also created in advance, at the start of their block, but they cannot be used before their line. In our picture their box is taped shut, and it can be opened only at the declaration line. The stretch from the start of the block to the declaration line is called the temporal dead zone, TDZ for short.
Press "Next step" and watch the order frame: total is in it from the first step of the call, while count gets its value only on its own line.
1function order() {2 console.log(total);3 var total = 10;4 console.log(total);5 let count = 3;6 console.log(count);7}8 9order();
The script calls order and waits for the call to finish.
If you touch the variable inside the dead zone, the program stops:
function order() {
console.log(count); // ✗
let count = 3;
}
order();ReferenceError: Cannot access 'count' before initializationThis is how Node.js and Chrome word the message. It differs from count is not defined: the name already exists but has not received its value yet. A function expression stored in a const gives the same message if you call it above that line: the constant already exists but holds no function yet.
This error shows up at once, while the undefined from a var passes unnoticed and spoils the calculations further down the code.
Interviewers often ask: "What are hoisting and the temporal dead zone?" A good answer names three cases:
- a function declaration is ready to call before the first line;
- a
varexists in advance and holdsundefineduntil its line; letandconstexist in advance, but touching them before their line gives aReferenceError.
Common mistake
A var variable is used in a calculation above its line:
function price() {
const total = base * 2; // ✗
var base = 50;
return total;
}
console.log(price());The program prints NaN, with no error. On the line with total, the variable base already exists but holds undefined, and undefined * 2 gives NaN. Move the declaration of base above the calculation.
If you declare base with let or const, the program stops on that same line with a ReferenceError.
Key points
- JavaScript creates a function's or file's variables in advance, before the first line, and this is called hoisting.
- A function declaration is hoisted whole, so the function can be called above its text.
- A
varholdsundefineduntil its line, and the assignment runs where it is written. letandconstare in the temporal dead zone until their line: touching them gives aReferenceError.
Subscribe to take the course
The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.