Learning Objectives

  • Understand what closures are in JavaScript
  • Learn about scope and variable accessibility
  • Differentiate between global, function, and block scope
  • Recognize closure patterns in code

What Is a Closure?

A closure is one of JavaScript's most powerful and misunderstood features. Simply put, a closure is a function that has access to variables from an outer (enclosing) function's scope, even after that outer function has finished executing.

Before we dive into closures, we need to understand scope - the context in which variables are accessible.

Understanding Scope

Scope determines where variables can be accessed in your code. JavaScript has three types of scope:

1. Global Scope

Variables declared outside any function are in the global scope and can be accessed anywhere:

const globalVar = "I'm global!";

function showGlobal() {
    console.log(globalVar); // Can access global variable
}

showGlobal(); // Output: "I'm global!"
console.log(globalVar); // Output: "I'm global!"

2. Function Scope

Variables declared inside a function are only accessible within that function:

function myFunction() {
    const localVar = "I'm local!";
    console.log(localVar); // Works fine
}

myFunction(); // Output: "I'm local!"
console.log(localVar); // Error: localVar is not defined

3. Block Scope (ES6+)

Variables declared with let or const inside a block {} are only accessible within that block:

if (true) {
    let blockVar = "I'm in a block!";
    const anotherBlockVar = "Me too!";
    console.log(blockVar); // Works fine
}

console.log(blockVar); // Error: blockVar is not defined

Your First Closure

Now that we understand scope, let's see a closure in action:

function outerFunction() {
    const outerVar = "I'm from outer!";
    
    function innerFunction() {
        console.log(outerVar); // Can access outerVar
    }
    
    return innerFunction;
}

const myClosure = outerFunction();
myClosure(); // Output: "I'm from outer!"

What just happened? Let's break it down:

  1. outerFunction declares a variable outerVar
  2. innerFunction is defined inside outerFunction
  3. innerFunction references outerVar from its parent scope
  4. outerFunction returns innerFunction
  5. We call outerFunction() and store the returned function in myClosure
  6. When we call myClosure(), it still has access to outerVar!

This is a closure! Even though outerFunction has finished executing, innerFunction still "remembers" and can access outerVar.

Why Do Closures Exist?

Closures exist because of JavaScript's lexical scoping. When a function is created, it retains a reference to its lexical environment (the scope in which it was created). This means the function can access variables from that environment, even if the outer function has completed.

A Practical Example

Let's see a more practical use of closures - creating a counter:

function createCounter() {
    let count = 0; // Private variable
    
    return {
        increment: function() {
            count++;
            return count;
        },
        decrement: function() {
            count--;
            return count;
        },
        getCount: function() {
            return count;
        }
    };
}

const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.decrement()); // 1
console.log(counter.getCount());  // 1

// Can't access count directly
console.log(counter.count); // undefined

This is powerful! The count variable is private - it can only be modified through the methods we've provided. This is called data encapsulation, and it's one of the most common uses of closures.

Visualizing Closures

┌─────────────────────────────────────┐ │ Global Scope │ │ │ │ ┌───────────────────────────────┐ │ │ │ outerFunction() │ │ │ │ │ │ │ │ outerVar = "I'm from outer!" │ │ │ │ │ │ │ │ ┌─────────────────────────┐ │ │ │ │ │ innerFunction() │ │ │ │ │ │ │ │ │ │ │ │ Can access outerVar ✓ │ │ │ │ │ │ │ │ │ │ │ └─────────────────────────┘ │ │ │ │ │ │ │ └───────────────────────────────┘ │ │ │ └─────────────────────────────────────┘

Key Takeaways

  • ✅ A closure is a function that accesses variables from an outer function's scope
  • Scope determines where variables can be accessed (global, function, block)
  • ✅ Closures "remember" their lexical environment
  • ✅ Closures enable data privacy and encapsulation
  • ✅ Inner functions have access to outer function variables, even after the outer function returns

Next Steps

Now that you understand what closures are and how scope works, in the next lesson we'll dive deeper into lexical scope and the scope chain to understand exactly how JavaScript resolves variable references.