JavaScript Scope & The Scope Chain
Understand where variables live, why curly braces lock in data with let and const, and how JavaScript finds variables.
1. What is Scope?
Scope simply answers one question: "Where in my code can I actually use this variable?"
💡 Think of rooms in a house
If you put a chair inside your bedroom (a function or {} block), people walking on the street outside cannot see or use your chair. But if something is placed in the open front yard (Global Scope), everyone in the entire house can see and use it.
Function Scope
Any variable created inside a function stays trapped inside that function.
function login() {
const token = "SECRET_123";
}
// console.log(token);
// ❌ Error: token is trapped inside login()
Block Scope (`let` & `const` ✅)
Any variable created with let or const stays locked inside curly braces {} (like if or for).
if (true) {
let role = "Admin";
}
// console.log(role);
// ❌ Error: role is trapped inside {}
2. Why `var` is Dangerous (It Ignores Curly Braces)
In old JavaScript, var did not care about if blocks or for loops. It would sneak out and pollute the rest of your code:
⚠️ The var Leakage Problem
If you create var score = 100 inside an if block, it escapes into the whole file. Always use let and const in modern JavaScript to keep your variables safely contained inside their curly braces.
// ❌ Old var leaks out of {} blocks:
if (true) {
var leaked = "I escaped!";
}
console.log(leaked); // "I escaped!" (Pollutes outer code!)
// ✅ Modern let stays safely trapped:
if (true) {
let safe = "I am locked in!";
}
// console.log(safe); // ❌ Error: safe is not defined
I escaped!
3. The Scope Chain (How JavaScript Finds Variables)
When JavaScript needs to read a variable, it looks inside your code like someone searching for their keys:
- Step 1: It checks the current room (local scope). If found, it uses it!
- Step 2: If not found, it steps outside into the parent room (enclosing function).
- Step 3: If still not found, it checks the whole house (global scope).
- Step 4: If it still can't find it anywhere, it stops and gives you a
ReferenceError!
const globalName = "Earth";
function country() {
const countryName = "India";
function city() {
const cityName = "Mumbai";
// The inner function can see everything outside it:
console.log(`${cityName} is in ${countryName}, on planet ${globalName}`);
}
city();
}
country();
Mumbai is in India, on planet Earth
4. Variable Shadowing (Hiding an Outer Variable)
If an inner block creates a variable with the exact same name as an outer variable, the inner variable temporarily hides (shadows) the outer one inside that block:
const theme = "dark"; // Outer global theme
function setCustomTheme() {
const theme = "light"; // Shadows the outer "dark" theme inside this function!
console.log("Inside function theme is:", theme); // "light"
}
setCustomTheme();
console.log("Outside in global theme is:", theme); // "dark" (Untouched!)
Inside function theme is: light Outside in global theme is: dark
5. Strict Mode: Preventing Accidental Global Variables
If you mistype a variable name without let or const (like myScore = 100), old JavaScript would accidentally create a global variable! Writing "use strict" at the top prevents this by throwing an immediate error:
function testSafety() {
"use strict";
try {
// Mistyped without let or const
score = 99;
} catch (err) {
console.log("Strict mode caught the typo:", err.message);
}
}
testSafety();
Strict mode caught the typo: score is not defined
6. Quick Scope Summary
| Scope | Where it lives | Who can access it? |
|---|---|---|
| Global Scope | Outside all functions and blocks | Accessible by any code anywhere in the file |
| Function Scope | Inside a function() {} |
Only accessible inside that specific function |
| Block Scope | Inside curly braces {} with let or const |
Only accessible inside those curly braces |
7. Scope Interview Deck
Test your knowledge on block scope traps, lexical scope lookup, shadowing, TDZ in functions, and strict mode:
8. Practice Challenge
🎯 Coding Challenge: 3-Level Scope Hierarchy
Build a 3-level scope chain:
1. A global constant appName = "DevHub".
2. A function-scoped constant version = "1.0.0" inside initializeApp().
3. A block-scoped variable build = "Release-92" inside an if (true) block.
Print all 3 values together from inside the deepest block.