💻 Programming intermediate

Closure

A function that retains access to variables from its outer scope even after that scope has finished executing.

What is a Closure?

A closure is a function bundled together with its lexical environment—the variables that were in scope when the function was created. This allows the inner function to "remember" and access those variables even after the outer function has returned.

How Closures Work

When a function is defined inside another function, it forms a closure by capturing variables from the outer scope:

function createCounter() {
    let count = 0;  // This variable is "enclosed"

    return function() {
        count++;    // Inner function accesses outer variable
        return count;
    };
}

const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3

The inner function maintains a reference to count even after createCounter() has finished executing.

Common Use Cases

1. Data Privacy / Encapsulation

function createBankAccount(initialBalance) {
    let balance = initialBalance;  // Private variable

    return {
        deposit: (amount) => { balance += amount; },
        withdraw: (amount) => { balance -= amount; },
        getBalance: () => balance
    };
}

const account = createBankAccount(100);
account.deposit(50);
console.log(account.getBalance()); // 150
// balance is not directly accessible

2. Function Factories

function multiply(factor) {
    return (number) => number * factor;
}

const double = multiply(2);
const triple = multiply(3);

console.log(double(5));  // 10
console.log(triple(5));  // 15

3. Event Handlers with State

function setupButton(buttonId) {
    let clickCount = 0;

    document.getElementById(buttonId).addEventListener("click", () => {
        clickCount++;
        console.log(`Clicked ${clickCount} times`);
    });
}

Python Closures

def make_multiplier(n):
    def multiplier(x):
        return x * n  # n is captured from outer scope
    return multiplier

double = make_multiplier(2)
print(double(5))  # 10

Closures vs Classes

Aspect Closures Classes
Syntax Lighter, functional More verbose
State Implicitly captured Explicit with self
Memory One closure per instance Shared methods
Use case Simple state, callbacks Complex objects

Common Pitfalls

Loop Variable Capture

// Problem: All functions share the same i
for (var i = 0; i < 3; i++) {
    setTimeout(() => console.log(i), 100);
}
// Prints: 3, 3, 3

// Solution: Use let (block scope) or IIFE
for (let i = 0; i < 3; i++) {
    setTimeout(() => console.log(i), 100);
}
// Prints: 0, 1, 2

Memory Considerations

Closures keep their enclosed variables alive, which can lead to memory leaks if not managed properly. Variables in a closure won't be garbage collected until the closure itself is no longer referenced.

// Example Usage

React hooks like useState use closures to maintain state between renders without exposing it globally.