Scope & Hoisting

📖 Concept

Scope determines where variables are accessible. JavaScript has 3 types:

  1. Global scope — Variables declared outside any function/block. Accessible everywhere.
  2. Function scope — Variables declared with var inside a function. Accessible only within that function.
  3. Block scope — Variables declared with let/const inside {}. Accessible only within that block.

Hoisting is JavaScript's behavior of moving declarations to the top of their scope during compilation (before execution):

  • var declarations are hoisted and initialized as undefined
  • let/const declarations 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

codeTap to expand ⛶
1// Global scope
2const globalVar = "I'm global";
3
4function outer() {
5 // Function scope
6 var functionVar = "I'm function-scoped";
7
8 if (true) {
9 // Block scope
10 let blockLet = "I'm block-scoped";
11 const blockConst = "Me too";
12 var notBlock = "I'm NOT block-scoped!"; // var ignores blocks
13 }
14
15 console.log(notBlock); // ✅ Works — var is function-scoped
16 // console.log(blockLet); // ❌ ReferenceError — let is block-scoped
17}
18
19// Hoisting examples
20console.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;
24
25// Function hoisting
26sayHello(); // ✅ Works! Function declarations are fully hoisted
27function sayHello() {
28 console.log("Hello!");
29}
30
31// sayBye(); // ❌ TypeError: sayBye is not a function
32var sayBye = function() {
33 console.log("Bye!");
34};
35
36// Scope chain — inner scopes can access outer scopes
37function outerFn() {
38 const outerVal = "outer";
39 function innerFn() {
40 const innerVal = "inner";
41 console.log(outerVal); // ✅ Can access outer scope
42 console.log(innerVal); // ✅ Own scope
43 }
44 innerFn();
45 // console.log(innerVal); // ❌ Can't access inner scope
46}
47
48// Closure preview — function remembers its scope
49function counter() {
50 let count = 0;
51 return function() {
52 return ++count;
53 };
54}
55const inc = counter();
56console.log(inc()); // 1
57console.log(inc()); // 2

🏋️ Practice Exercise

Mini Exercise:

  1. Predict the output of a script with mixed var, let, and function declarations
  2. Write code that demonstrates the Temporal Dead Zone
  3. Create a function that demonstrates the scope chain (3 levels deep)
  4. Explain why the classic var in a for-loop with setTimeout prints the same number

⚠️ Common Mistakes

  • Assuming let and const are not hoisted — they ARE hoisted, but stay in the Temporal Dead Zone until declared

  • Not understanding that var inside an if or for block is still function-scoped, not block-scoped

  • Confusing function declaration hoisting (fully hoisted) with function expression hoisting (only the var is hoisted)

  • Accidentally creating global variables by forgetting let/const/var — in non-strict mode, x = 5 creates a global

  • Not knowing that each let in a for-loop creates a NEW binding per iteration, while var shares one

💼 Interview Questions

🎤 Mock Interview

Mock interview is powered by AI for Scope & Hoisting. Login to unlock this feature.