Hoisting: var, let, const & Functions
18 min read
HoistingTDZvar vs let vs constFunction DeclarationsBlock ScopeFunction Scope
What is Hoisting?
Hoisting is JavaScript's behavior of moving declarations (not assignments) to the top of their scope during the Creation Phase of the execution context.
How Different Declarations Are Hoisted
| Declaration | Hoisted? | Initial Value | Scope |
|---|---|---|---|
var | ✅ Yes | undefined | Function |
let | ✅ Yes (but TDZ) | Uninitialized | Block |
const | ✅ Yes (but TDZ) | Uninitialized | Block |
function | ✅ Yes (fully) | Entire function | Function |
class | ✅ Yes (but TDZ) | Uninitialized | Block |
The Temporal Dead Zone (TDZ)
The TDZ is the period between entering a scope and the variable's declaration being executed. Accessing a let or const variable in its TDZ throws a ReferenceError.
// TDZ for `name` starts here
console.log(name); // ❌ ReferenceError: Cannot access 'name' before initialization
let name = "Alice"; // TDZ ends hereFunction Hoisting vs Expression Hoisting
// ✅ Function Declaration — fully hoisted
greet(); // Works! "Hello"
function greet() { console.log("Hello"); }
// ❌ Function Expression — only var is hoisted (as undefined)
sayHi(); // TypeError: sayHi is not a function
var sayHi = function() { console.log("Hi"); };
// ❌ Arrow Function with const — TDZ
sayBye(); // ReferenceError
const sayBye = () => console.log("Bye");Why var Causes Bugs
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
// Output: 3, 3, 3 (var is function-scoped, shares one `i`)
for (let j = 0; j < 3; j++) {
setTimeout(() => console.log(j), 100);
}
// Output: 0, 1, 2 (let is block-scoped, each iteration gets its own `j`)Best Practices
- Use
constby default - Use
letonly when you need reassignment - Never use
varin modern JavaScript - Declare variables at the top of their scope for clarity