JavaScript Guide
Intermediate13 minsJS Tutorial

JavaScript Scope

Understand JavaScript scope completely — global scope, function scope, block scope, lexical scope, and how scope chains work.

Lesson session

0% complete

0/5
Learn mode

Read the concept first, then inspect syntax and examples.

Study prompt

Current mode guidance

Read the concept first, then inspect syntax and examples.

Confidence

Track your comfort

55%
NewClear

Quick notes

0/240 characters

Concept switcher

Move through the idea before the code.

Scope determines WHERE in your code a variable is accessible. It answers the question: "Can I use this variable here?"

JavaScript has three types of scope:

| Scope | Created by | Accessible |

|-------|------------|-----------|

| **Global** | Outside all functions/blocks | Everywhere in the file |

| **Function** | Inside a `function` body | Only inside that function |

| **Block** | Inside `{ }` with `let`/`const` | Only inside that block |

Why scope matters:

Variables in different scopes can have the same name without conflict

Scope protects variables from being accidentally modified by unrelated code

Understanding scope is REQUIRED for debugging "variable is not defined" errors

Scope is the foundation of closures, modules, and encapsulation

Example preview

Run it in your head

Global, Function, and Block Scope Side by Side

See exactly where variables are and aren't accessible.

const globalMessage = "I'm global"; // Global scope

function outerFunction() {
  const outerVar = "I'm in outer"; // Function scope
  
  if (true) {
    const blockVar = "I'm in block"; // Block scope
    let anotherBlock = "also block";
    
    // ✅ Can access all three scopes
    console.log("Inside block:", globalMessage);
    console.log("Inside block:", outerVar);
    console.log("Inside block:", blockVar);
  }
  
  // ✅ Can access global and function scope
  console.log("Inside outer:", globalMessage);
  console.log("Inside outer:", outerVar);
  // ❌ Cannot access block scope
  // console.log(blockVar); // ReferenceError!
}

// ✅ Can access only global
console.log("Global level:", globalMessage);
// ❌ Cannot access function or block scope
// console.log(outerVar); // ReferenceError!

outerFunction();
Output

Predict the output first, then reveal it.

Next useful links

Related pages from the same JavaScript guide.

Overview & Purpose

Scope determines WHERE in your code a variable is accessible. It answers the question: "Can I use this variable here?"

JavaScript has three types of scope:

| Scope | Created by | Accessible |

|-------|------------|-----------|

| **Global** | Outside all functions/blocks | Everywhere in the file |

| **Function** | Inside a `function` body | Only inside that function |

| **Block** | Inside `{ }` with `let`/`const` | Only inside that block |

Why scope matters:

Variables in different scopes can have the same name without conflict

Scope protects variables from being accidentally modified by unrelated code

Understanding scope is REQUIRED for debugging "variable is not defined" errors

Scope is the foundation of closures, modules, and encapsulation

Topic Definition

Scope is the region of code where a variable is defined and accessible.

Think of it like buildings:

Global scope = the street (everyone can access)

Function scope = a private office (only people inside)

Block scope = a locked cabinet inside the office

Global scope
├── globalVar = "I'm everywhere"
│
├── function outer() {
│   ├── outerVar = "I'm in outer only"
│   │
│   └── function inner() {
│       ├── innerVar = "I'm in inner only"
│       └── Can access: innerVar, outerVar, globalVar ✅
│   }
│   Can access: outerVar, globalVar ✅
│   Cannot access: innerVar ❌
│}
│
Can access: globalVar ✅
Cannot access: outerVar, innerVar ❌

This layered access is called the scope chain — inner scopes can access outer scopes, but not vice versa.

Why It Matters

Understanding scope prevents three categories of bugs:

1. "Variable is not defined" errors — you're trying to use a variable outside its scope

2. Variable collision — two different var declarations overwrite each other

3. Unexpected global variables — forgetting const/let creates a global variable

Real consequence example:

for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
// Output: 3, 3, 3 (NOT 0, 1, 2!)
// Because var is function-scoped — all timeouts share the SAME i

for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
// Output: 0, 1, 2 ✅
// Because let is block-scoped — each iteration has its OWN i

This is one of the most classic JavaScript interview questions!

Syntax Guide

javascript
// ═══════════════════════════════════════════════
// 1. GLOBAL SCOPE
// ═══════════════════════════════════════════════
const appName = "MyApp";         // Global — accessible everywhere
let currentUser = null;          // Global — changes throughout session

// ═══════════════════════════════════════════════
// 2. FUNCTION SCOPE
// ═══════════════════════════════════════════════
function processOrder(order) {
  const discount = 0.10;         // Function-scoped — only here
  const total = order.price * (1 - discount);
  return total;
  // discount and total DON'T exist outside this function
}

// ═══════════════════════════════════════════════
// 3. BLOCK SCOPE (let/const)
// ═══════════════════════════════════════════════
if (true) {
  const blockVar = "I'm block-scoped";
  let counter = 0;
  console.log(blockVar); // ✅ accessible inside block
}
// console.log(blockVar); // ❌ ReferenceError outside block

// ═══════════════════════════════════════════════
// 4. SCOPE CHAIN (inner accesses outer)
// ═══════════════════════════════════════════════
const taxRate = 0.18;            // Outer scope

function calculatePrice(base) {
  const withTax = base * (1 + taxRate); // ✅ accesses outer taxRate
  
  function formatPrice() {
    return "₹" + withTax.toFixed(2);    // ✅ accesses parent's withTax
  }
  
  return formatPrice();
}
console.log(calculatePrice(1000));
Reference API Specifications
Parameters:
  • Global scope — variables declared outside all functions, accessible everywhere
  • Function scope — variables declared with var inside a function, accessible only in that function
  • Block scope — variables declared with let/const inside {}, accessible only in that block
  • Scope chain — JavaScript looks up the chain of parent scopes to find variables
  • Lexical scope — scope is determined at write-time by code structure, not runtime
Return Value:

Scope is a concept, not a function. Variables either are or aren't accessible based on where they're declared.

Syntax Explanation:

The Scope Chain in detail:

When JavaScript encounters a variable, it searches in this order:

1. Current scope (local)

2. Parent scope

3. Grandparent scope

4. ...continue up

5. Global scope

6. If not found → ReferenceError

Global: taxRate = 0.18
  └─ outer(): base = 1000
       ├─ reads taxRate from global ✅
       └─ inner():
            ├─ reads base from outer ✅
            └─ reads taxRate from global ✅

Variable Shadowing:

When an inner scope declares a variable with the same name as an outer scope, the inner one "shadows" the outer:

const name = "Global Asha";

function greet() {
  const name = "Local Ravi"; // shadows the global name
  console.log(name); // "Local Ravi" — local wins
}

greet();
console.log(name); // "Global Asha" — global unchanged

Runnable Code Examples

Example 1: Global, Function, and Block Scope Side by Side

See exactly where variables are and aren't accessible.

javascript
const globalMessage = "I'm global"; // Global scope

function outerFunction() {
  const outerVar = "I'm in outer"; // Function scope
  
  if (true) {
    const blockVar = "I'm in block"; // Block scope
    let anotherBlock = "also block";
    
    // ✅ Can access all three scopes
    console.log("Inside block:", globalMessage);
    console.log("Inside block:", outerVar);
    console.log("Inside block:", blockVar);
  }
  
  // ✅ Can access global and function scope
  console.log("Inside outer:", globalMessage);
  console.log("Inside outer:", outerVar);
  // ❌ Cannot access block scope
  // console.log(blockVar); // ReferenceError!
}

// ✅ Can access only global
console.log("Global level:", globalMessage);
// ❌ Cannot access function or block scope
// console.log(outerVar); // ReferenceError!

outerFunction();
expected console output
Global level: I'm global Inside block: I'm global Inside block: I'm in outer Inside block: I'm in block Inside outer: I'm global Inside outer: I'm in outer
Breakdown:

Inner scopes can always reach up to outer/global scopes. Outer scopes cannot access inner scopes. This is called lexical scoping — determined by where the code is written.

Example 2: The Classic var vs let Loop Problem

One of the most asked JavaScript interview questions — why does this happen?

javascript
// ❌ var: all callbacks share the SAME i
console.log("Using var:");
for (var i = 0; i < 3; i++) {
  setTimeout(function() {
    console.log("var i =", i);
  }, 100 * i);
}

// ✅ let: each iteration has its OWN i
console.log("Using let (after 500ms delay):");
for (let j = 0; j < 3; j++) {
  setTimeout(function() {
    console.log("let j =", j);
  }, 500 + 100 * j);
}
expected console output
Using var: var i = 3 var i = 3 var i = 3 Using let (after 500ms delay): let j = 0 let j = 1 let j = 2
Breakdown:

var is function-scoped — all 3 setTimeout callbacks share the SAME i variable. By the time they run (after 100ms+), the loop is done and i = 3. let is block-scoped — each iteration creates a NEW i variable, capturing the value at that moment.

Example 3: Scope Chain — How JavaScript Finds Variables

Watch JavaScript climb the scope chain to find a variable.

javascript
// Level 1: Global scope
const currency = "₹";

function showPricing() {
  // Level 2: Function scope
  const taxRate = 0.18;
  
  function formatPrice(amount) {
    // Level 3: Inner function scope
    const withTax = amount * (1 + taxRate);
    // Accesses: amount (own), taxRate (parent), currency (grandparent/global)
    return currency + withTax.toFixed(2);
  }
  
  function applyDiscount(price, pct) {
    // Also Level 2 — can access taxRate (sibling scope? No — parent scope)
    const discounted = price * (1 - pct);
    const formatted = formatPrice(discounted); // Call sibling function
    return formatted;
  }
  
  console.log("Full price:", formatPrice(1000));
  console.log("After 10% discount:", applyDiscount(1000, 0.10));
}

showPricing();
expected console output
Full price: ₹1180.00 After 10% discount: ₹1062.00
Breakdown:

formatPrice() can access taxRate from showPricing() (parent) and currency from global scope (grandparent). This chain — local → parent → grandparent → global — is the scope chain. JavaScript searches up until it finds the variable or throws ReferenceError.

Real-world Use Cases

  • 1

    Module pattern: Using function scope to create private variables that external code can't accidentally modify — the basis of encapsulation.

  • 2

    Event handler bugs: Variables declared with var in loops that are shared across all event handlers — a common bug fixed by using let.

  • 3

    React hooks: useState values are scoped to the component function. Understanding scope helps you know why state updates work the way they do.

  • 4

    Avoiding global pollution: Wrapping code in functions or modules (IIFE) prevents adding to the global scope, preventing conflicts with third-party scripts.

  • 5

    Configuration objects: Global constants like const API_BASE_URL are deliberately global; component-level data should be locally scoped.

  • 6

    Debugging 'undefined' errors: 90% of 'variable is not defined' errors are scope issues — the variable exists in a different scope.

Coding Exercises

1

Exercise Challenge

Predict the output before running: var x = 1; function fn() { var x = 2; console.log(x); } fn(); console.log(x);

2

Exercise Challenge

Fix the classic loop closure bug to log 0, 1, 2 instead of 3, 3, 3.

Practice Tasks Checklist

1Create a function with a local variable. Try to access the variable outside — confirm you get ReferenceError.
2Demonstrate the var-in-loop bug (3,3,3) and fix it with let (0,1,2).
3Create a scope chain: global → outer function → inner function, and show what each level can access.
4Create two functions with local variables of the same name. Show they don't interfere.
5Identify 3 places in a project where you should replace global variables with locally-scoped ones.
6Create an IIFE that protects private variables from global scope.
7Use Chrome DevTools Scope panel to inspect variables at a breakpoint.
8Explain variable shadowing with a working code example.
9Create a factory function using closure to maintain private state.
10Show that var leaks out of if blocks but let doesn't.

JavaScript Scope Quiz Challenges

1

Quiz Challenge

Can an inner function access variables from its outer function?

2

Quiz Challenge

What type of scope does a variable declared with var inside an if block have?

3

Quiz Challenge

What is variable shadowing?

Technical Interview Q&As

1What is scope in JavaScript?

Model Answer:

Scope is the region of code where a variable is accessible. JavaScript has three scope levels: Global (accessible everywhere), Function (accessible inside the function), and Block (accessible inside {} with let/const). Inner scopes can access outer/global scopes (scope chain), but not vice versa.
2What is the difference between var, let, and const regarding scope?

Model Answer:

var is function-scoped — it exists throughout the entire function regardless of which block it's declared in. let and const are block-scoped — they only exist within the {} they're declared in. This makes var unpredictable in loops and if blocks, while let/const behave as you'd expect.
3What is the scope chain?

Model Answer:

When JavaScript looks up a variable, it first checks the current scope. If not found, it checks the parent scope, then grandparent, all the way to global scope. If not found anywhere, it throws ReferenceError. This lookup path is the scope chain. Inner functions can always access variables from their outer functions — this is the basis of closures.
4Why does `for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 0) }` log 3, 3, 3?

Model Answer:

var is function-scoped. All three setTimeout callbacks share the SAME i variable. The loop completes (i becomes 3) before any timeout runs. When they do run, they all read i which is now 3. Fix: use let instead of var. let is block-scoped — each loop iteration creates a NEW i, capturing the value at that moment. Result: 0, 1, 2.

Related Lessons

Frequently Asked Questions