JavaScript Course Lesson 14 of 16
The Codex / JavaScript / Scope & Closures

Scope & Closures

Where variables live, how functions remember their surroundings, and the closure pattern that powers callbacks and modules.

What it is, in plain English: Scope is the part of your code where a variable exists and can be used. In JavaScript, variables declared with let and const are block-scoped — they only live inside the { } block where they were created. A closure happens when a function remembers the variables from the scope where it was defined, even after that scope has finished running. Closures are how JavaScript functions carry their context with them — it's the foundation of callbacks, event handlers, and modules.

Where variables exist — and how functions remember their home

Scope — the "visibility zone" of a variable

Every variable has a scope — the region of code where it exists. Outside that region, the variable doesn't exist, and trying to use it causes an error.

// Global scope — declared outside any function or block
const appName = "My App";   // visible everywhere in this file

function showName() {
  // Function scope — declared inside a function
  const localGreeting = "Hello";  // only visible inside showName()
  console.log(localGreeting + " from " + appName);  // both visible here
}

showName();  // "Hello from My App"
// console.log(localGreeting);  // ✗ ReferenceError — doesn't exist out here
// Block scope — let/const declared inside { } stay inside { }
if (true) {
  let insideIf = "I only exist in here";
  const alsoInside = "Me too";
  console.log(insideIf);     // ✓ works
}
// console.log(insideIf);   // ✗ ReferenceError

for (let i = 0; i < 3; i++) {
  // i only exists inside this loop
}
// console.log(i);  // ✗ ReferenceError

The scope chain — looking things up

When JavaScript looks for a variable, it starts in the current scope, then looks in the parent scope, then its parent, all the way up to global scope. This is the scope chain.

const greeting = "Hello";         // global

function outer() {
  const name = "Alice";           // outer's scope

  function inner() {
    const punctuation = "!";      // inner's scope
    // inner can see ALL of these:
    console.log(greeting + ", " + name + punctuation);   // "Hello, Alice!"
  }

  inner();
  // outer can't see punctuation — it's in inner's scope
}

outer();

Closures — a function that remembers its home

A closure happens when a function is defined inside another function and keeps a reference to the outer function's variables — even after the outer function has finished running.

function makeGreeter(greeting) {
  // When makeGreeter finishes, 'greeting' would normally disappear.
  // But the returned function CLOSES OVER it — keeps it alive.

  return function(name) {
    console.log(`${greeting}, ${name}!`);  // still has access to greeting
  };
}

const sayHello   = makeGreeter("Hello");
const sayNamaste = makeGreeter("Namaste");

sayHello("Alice");     // "Hello, Alice!"
sayNamaste("Bob");     // "Namaste, Bob!"
sayHello("Charlie");   // "Hello, Charlie!"  — greeting is still "Hello"

Think of a closure as a function with a backpack. When it leaves the place where it was born, it takes a copy of the surrounding variables with it in that backpack.

The loop + setTimeout trap (and how closures explain it)

// Classic trap with var — all callbacks share the same i:
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
// Prints: 3, 3, 3  — by the time the callbacks run, loop is done and i=3

// Fix 1: use let — creates a new i for each iteration
for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
// Prints: 0, 1, 2  ✓

// Fix 2: closure to capture the current value (pre-ES6 style)
for (var i = 0; i < 3; i++) {
  (function(j) {          // j is a new variable for each iteration
    setTimeout(() => console.log(j), 100);
  })(i);
}
// Prints: 0, 1, 2  ✓
This is why let replaced var. let creates a fresh binding for each loop iteration. var shares one binding across all iterations. Use let in loops, always.
Try It Yourself

Official Sources

The Codex links only to official documentation and the ECMAScript specification. No third-party tutorials.