Scope & Hoisting
📖 Concept
Scope determines where variables are accessible. JavaScript has 3 types:
- Global scope — Variables declared outside any function/block. Accessible everywhere.
- Function scope — Variables declared with
varinside a function. Accessible only within that function. - Block scope — Variables declared with
let/constinside{}. Accessible only within that block.
Hoisting is JavaScript's behavior of moving declarations to the top of their scope during compilation (before execution):
vardeclarations are hoisted and initialized asundefinedlet/constdeclarations are hoisted but NOT initialized (Temporal Dead Zone)- Function declarations are hoisted completely (name + body)
- Function expressions and arrow functions are NOT hoisted
🏠 Real-world analogy: Scope is like rooms in a house. A variable in the living room (global) can be seen from anywhere. One in the bedroom (function) is only visible there. Hoisting is like the house butler who moves all the furniture labels to the top of each room before you walk in.
💻 Code Example
1// Global scope2const globalVar = "I'm global";34function outer() {5 // Function scope6 var functionVar = "I'm function-scoped";78 if (true) {9 // Block scope10 let blockLet = "I'm block-scoped";11 const blockConst = "Me too";12 var notBlock = "I'm NOT block-scoped!"; // var ignores blocks13 }1415 console.log(notBlock); // ✅ Works — var is function-scoped16 // console.log(blockLet); // ❌ ReferenceError — let is block-scoped17}1819// Hoisting examples20console.log(a); // undefined (var is hoisted, initialized as undefined)21// console.log(b); // ❌ ReferenceError (TDZ — let is hoisted but not initialized)22var a = 1;23let b = 2;2425// Function hoisting26sayHello(); // ✅ Works! Function declarations are fully hoisted27function sayHello() {28 console.log("Hello!");29}3031// sayBye(); // ❌ TypeError: sayBye is not a function32var sayBye = function() {33 console.log("Bye!");34};3536// Scope chain — inner scopes can access outer scopes37function outerFn() {38 const outerVal = "outer";39 function innerFn() {40 const innerVal = "inner";41 console.log(outerVal); // ✅ Can access outer scope42 console.log(innerVal); // ✅ Own scope43 }44 innerFn();45 // console.log(innerVal); // ❌ Can't access inner scope46}4748// Closure preview — function remembers its scope49function counter() {50 let count = 0;51 return function() {52 return ++count;53 };54}55const inc = counter();56console.log(inc()); // 157console.log(inc()); // 2
🏋️ Practice Exercise
Mini Exercise:
- Predict the output of a script with mixed
var,let, and function declarations - Write code that demonstrates the Temporal Dead Zone
- Create a function that demonstrates the scope chain (3 levels deep)
- Explain why the classic
varin a for-loop with setTimeout prints the same number
⚠️ Common Mistakes
Assuming
letandconstare not hoisted — they ARE hoisted, but stay in the Temporal Dead Zone until declaredNot understanding that
varinside aniforforblock is still function-scoped, not block-scopedConfusing function declaration hoisting (fully hoisted) with function expression hoisting (only the
varis hoisted)Accidentally creating global variables by forgetting
let/const/var— in non-strict mode,x = 5creates a globalNot knowing that each
letin a for-loop creates a NEW binding per iteration, whilevarshares one
💼 Interview Questions
🎤 Mock Interview
Mock interview is powered by AI for Scope & Hoisting. Login to unlock this feature.