Hoisting Pitfalls and Bugs to Avoid in JavaScript
Hoisting causes real bugs if you ignore it. Here are the most common pitfalls and how to write code that avoids them.
Hoisting Pitfalls and Bugs to Avoid in JavaScript
Hoisting can cause subtle bugs if you ignore how it works. Here are the most common pitfalls and how to avoid them.
Pitfall 1: Using a Variable Before Assignment
function calculate() { total = total + 10; // NaN or ReferenceError in strict mode var total = 0; return total; }
total is hoisted with undefined. undefined + 10 is NaN. In strict mode (modules), assigning to an undeclared variable throws.
Fix: Declare and initialize at the top.
function calculate() { let total = 0; total = total + 10; return total; }
Pitfall 2: Loop Variables Leaking With var
for (var i = 0; i < 3; i++) {} console.log(i); // 3
var is function-scoped, so i leaks out of the loop. With let, it stays block-scoped.
Fix: Use let in loops.
Pitfall 3: Function Expression Called Too Early
doWork(); var doWork = function () { ... };
Throws TypeError: doWork is not a function.
Fix: Use const for function expressions and never call them before declaration.
const doWork = () => { ... }; doWork();
Pitfall 4: Shadowing a Variable Unintentionally
var name = "Kunal"; function greet() { console.log(name); // undefined var name = "Asha"; } greet();
The inner var name is hoisted, shadowing the outer one. The first log sees undefined, not "Kunal".
Fix: Use let and pick distinct names.
Pitfall 5: Relying on var Re-declaration
var x = 1; var x = 2; // silent, no error
This hides typos and duplicate declarations.
Fix: Use let or const. They throw on re-declaration in the same scope.
Pitfall 6: TDZ Surprises With let/const
function foo(a = b, b = 2) { return a + b; } foo(); // ReferenceError
Fix: Reorder parameters or avoid cross-references in defaults.
Best Practices
- Use
constby default,letwhen you must reassign, avoidvar. - Declare variables at the top of their scope.
- Use function expressions with
constfor predictable behavior. - Enable strict mode (
"use strict"or ES modules) to catch silent bugs.
The Takeaway
Hoisting pitfalls include NaN from early use, var leaking out of loops, TypeError from early function expression calls, shadowing, and TDZ surprises. Use const/let, declare at the top, and enable strict mode to avoid them.
Using a var before assignment (returns undefined or NaN), var leaking out of loops, calling a function expression before assignment (TypeError), accidental shadowing, and TDZ surprises with let and const.
Use const by default and let when you must reassign, avoid var, declare variables at the top of their scope, use const for function expressions, and enable strict mode to catch silent issues.
Because var is function-scoped, not block-scoped. The loop variable exists in the enclosing function (or global scope). Using let makes the variable block-scoped and confined to the loop.
Because the var variable is hoisted with undefined. The variable exists, so no ReferenceError, but undefined() throws TypeError: x is not a function. Use const and declare before calling.
When an inner var declaration has the same name as an outer variable. The inner one is hoisted with undefined, so reads before the assignment line see undefined, not the outer value. Use let with distinct names to avoid it.
Ready to master React completely?
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.
Master React
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course.

