JavaScript Hoisting
What is Hoisting?โ
Hoisting is JavaScript's default behavior of moving declarations to the top of their scope during the compilation phase. Only declarations are hoisted, not initializations.
Variable Hoistingโ
var Hoistingโ
console.log(x); // undefined (not error)
var x = 5;
console.log(x); // 5
// What actually happens:
var x; // Declaration hoisted
console.log(x); // undefined
x = 5; // Assignment stays in place
console.log(x); // 5
let and const Hoisting (Temporal Dead Zone)โ
// console.log(y); // ReferenceError: Cannot access 'y' before initialization
let y = 10;
// console.log(z); // ReferenceError: Cannot access 'z' before initialization
const z = 20;
Function Hoistingโ
Function Declarationsโ
// This works - function is fully hoisted
sayHello(); // "Hello!"
function sayHello() {
console.log("Hello!");
}
Function Expressionsโ
// This doesn't work - only variable is hoisted
// sayGoodbye(); // TypeError: sayGoodbye is not a function
var sayGoodbye = function() {
console.log("Goodbye!");
};
sayGoodbye(); // "Goodbye!"
Arrow Functionsโ
// This doesn't work - behaves like function expressions
// greet(); // TypeError: greet is not a function
var greet = () => {
console.log("Hi!");
};
greet(); // "Hi!"
Practical Examplesโ
Example 1: Variable Hoistingโ
function example() {
console.log(a); // undefined (not error)
var a = 1;
console.log(a); // 1
}
// Equivalent to:
function example() {
var a; // Hoisted declaration
console.log(a); // undefined
a = 1; // Assignment in original position
console.log(a); // 1
}
Example 2: Function vs Variableโ
console.log(foo); // function foo() { return 'function'; }
var foo = 'variable';
function foo() {
return 'function';
}
console.log(foo); // 'variable'
// What happens:
// 1. Function declaration is hoisted completely
// 2. Variable declaration is hoisted (but not assignment)
// 3. Variable assignment overwrites function
Example 3: Scope and Hoistingโ
var name = "Global";
function test() {
console.log(name); // undefined (not "Global")
var name = "Local";
console.log(name); // "Local"
}
test();
// Explanation: Local 'name' declaration is hoisted,
// shadowing the global 'name' variable
Best Practicesโ
-
Always declare variables at the top of their scope
function goodPractice() {var a, b, c; // Declare at topa = 1;b = 2;c = 3;} -
Use let and const instead of var
// Avoid thisconsole.log(x); // undefinedvar x = 5;// Prefer thislet y = 5; // Clear and predictableconst z = 10; // Clear and predictable -
Declare functions before using them
// Good practicefunction myFunction() {return "Hello";}myFunction();
Common Gotchasโ
Loop with varโ
// Problem
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1000); // Prints 3, 3, 3
}
// Solution with let
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1000); // Prints 0, 1, 2
}
Multiple Declarationsโ
var a = 1;
function example() {
console.log(a); // undefined (not 1)
var a = 2;
}
// The local 'var a' declaration is hoisted,
// creating a local scope that shadows the global 'a'
Key Takeawaysโ
- Only declarations are hoisted, not assignments
varis hoisted and initialized withundefinedletandconstare hoisted but not initialized (TDZ)- Function declarations are completely hoisted
- Function expressions are not hoisted
- Always declare before use for better code clarity