Hoisting pitfalls and how to avoid them
JavaScriptThe short answer
Hoisting moves variable and function declarations to the top of their scope during compilation. The pitfalls come from the fact that var declarations are hoisted but initialized as undefined, while let and const are hoisted but not initialized at all (they sit in a "temporal dead zone"). Function declarations are fully hoisted, but function expressions are not.
Pitfall 1: Using var before declaration
console.log(name); // undefined — not an error!var name = 'John';console.log(name); // "John"JavaScript hoists var name to the top, but not the assignment. So the code actually runs like this:
var name; // hoisted — initialized as undefinedconsole.log(name); // undefinedname = 'John';console.log(name); // "John"This can cause silent bugs. You expect an error but get undefined instead, and the bug might go unnoticed.
Fix: Use let or const instead of var:
console.log(name); // ReferenceError: Cannot access 'name' before initializationlet name = 'John';With let and const, you get a clear error. This is much better because you catch the bug immediately.
Pitfall 2: The Temporal Dead Zone (TDZ)
let and const are hoisted, but they are not initialized. From the start of the block to the declaration, they are in a "temporal dead zone" where accessing them throws an error.
{ // TDZ starts console.log(x); // ReferenceError let x = 10; // TDZ ends console.log(x); // 10}This is actually a good thing. The TDZ forces you to declare variables before using them, which leads to cleaner code.
Pitfall 3: Function expressions are not hoisted like declarations
Function declarations are fully hoisted — you can call them before they appear in the code:
greet(); // "Hello" — works finefunction greet() { console.log('Hello');}But function expressions (where you assign a function to a variable) follow the rules of the variable:
greet(); // TypeError: greet is not a functionvar greet = function () { console.log('Hello');};var greet is hoisted as undefined. Calling undefined() gives a TypeError. If you use let or const, you get a ReferenceError instead (which is more helpful).
Pitfall 4: var in loops
for (var i = 0; i < 3; i++) { setTimeout(() => { console.log(i); }, 100);}// Output: 3, 3, 3 (not 0, 1, 2)var is function-scoped, not block-scoped. There is only one i variable for the entire loop. By the time the setTimeout callbacks run, i is already 3.
Fix: Use let — it is block-scoped, so each iteration gets its own i:
for (let i = 0; i < 3; i++) { setTimeout(() => { console.log(i); }, 100);}// Output: 0, 1, 2Pitfall 5: Hoisting in conditional blocks
With var, declarations are hoisted out of if blocks:
function test() { console.log(x); // undefined — not an error if (false) { var x = 10; // hoisted even though this block never runs } console.log(x); // undefined}The var x is hoisted to the top of the function even though the if block never executes. This is confusing and can lead to unexpected behavior.
How to avoid hoisting pitfalls
- Always use
letandconst— never usevar. This is the single most important rule. - Declare variables at the top of their scope — even with
let/const, it is good practice to declare them before you use them. - Use
constby default — only useletwhen you know the value will change. This prevents accidental reassignment. - Use function declarations for named functions — they are fully hoisted, which is predictable. Use arrow functions for callbacks.
Common Pitfalls
A common mistake in interviews is saying that let and const are not hoisted. They are hoisted — JavaScript knows about them. But they are not initialized, so accessing them before the declaration throws a ReferenceError. The correct term is "temporal dead zone." Saying they are not hoisted at all is technically incorrect.
Interview Tip
When answering hoisting questions, always compare var, let, and const. Show what happens with each when you access the variable before its declaration. The key takeaway is: var gives you undefined (silent bug), let/const give you an error (loud bug). Loud bugs are better because you catch them right away.
Why interviewers ask this
Hoisting is one of the quirky parts of JavaScript that causes real bugs. Interviewers want to see if you understand why var can be dangerous, if you know what the temporal dead zone is, and if you follow best practices like using let and const. It also tests your understanding of how JavaScript compiles and executes code, which is a fundamental concept.