Closures

Program demonstrating closures in JavaScript

JavaScriptIntermediate
JavaScript
// Closure: Function has access to outer function's variables

// Example 1: Basic closure
function outerFunction(x) {
    // Outer function's variable
    let outerVar = x;
    
    // Inner function (closure)
    function innerFunction(y) {
        console.log("Outer:", outerVar, "Inner:", y);
        return outerVar + y;
    }
    
    return innerFunction;
}

let closure = outerFunction(10);
console.log("Result:", closure(5));

// Example 2: Counter using closure
function createCounter() {
    let count = 0;
    
    return function() {
        count++;
        return count;
    };
}

let counter1 = createCounter();
let counter2 = createCounter();

console.log("\nCounter 1:", counter1());
console.log("Counter 1:", counter1());
console.log("Counter 2:", counter2());
console.log("Counter 1:", counter1());

// Example 3: Private variables
function createBankAccount(initialBalance) {
    let balance = initialBalance; // Private variable
    
    return {
        deposit: function(amount) {
            balance += amount;
            return balance;
        },
        withdraw: function(amount) {
            if (amount <= balance) {
                balance -= amount;
                return balance;
            } else {
                return "Insufficient funds";
            }
        },
        getBalance: function() {
            return balance;
        }
    };
}

let account = createBankAccount(100);
console.log("\nInitial balance:", account.getBalance());
console.log("After deposit 50:", account.deposit(50));
console.log("After withdraw 30:", account.withdraw(30));
console.log("Final balance:", account.getBalance());

// Example 4: Function factory
function createMultiplier(multiplier) {
    return function(number) {
        return number * multiplier;
    };
}

let double = createMultiplier(2);
let triple = createMultiplier(3);

console.log("\nDouble 5:", double(5));
console.log("Triple 5:", triple(5));

// Example 5: Closure with loop (common mistake)
console.log("\nClosure in loop:");
for (var i = 0; i < 3; i++) {
    setTimeout(function() {
        console.log("var i:", i); // Prints 3, 3, 3
    }, 100);
}

// Solution: Use let
for (let j = 0; j < 3; j++) {
    setTimeout(function() {
        console.log("let j:", j); // Prints 0, 1, 2
    }, 200);
}

Output

Outer: 10 Inner: 5
Result: 15

Counter 1: 1
Counter 1: 2
Counter 2: 1
Counter 1: 3

Initial balance: 100
After deposit 50: 150
After withdraw 30: 120
Final balance: 120

Double 5: 10
Triple 5: 15

Closure in loop:
var i: 3
var i: 3
var i: 3
let j: 0
let j: 1
let j: 2

This program demonstrates closures in JavaScript.

Closure Definition

A closure is a function that has access to variables in its outer (enclosing) scope, even after the outer function has returned.

Example 1: Basic Closure

Inner function accesses outer variable:

javascript
function outer(x) {
    let outerVar = x;
    return function inner(y) {
        return outerVar + y; // Accesses outerVar
    };
}

How it works:

  • Inner function "remembers" outer scope
  • Variables persist after outer function returns

Example 2: Counter

Each closure has its own state:

javascript
function createCounter() {
    let count = 0;
    return function() {
        return ++count;
    };
}

Key Point: Each call to createCounter() creates a new closure with its own count variable.

Example 3: Private Variables

Encapsulation pattern:

javascript
function createBankAccount(balance) {
    return {
        deposit: function(amount) {
            balance += amount; // Accesses private balance
        }
    };
}

Benefits:

  • Data privacy
  • Prevents external modification
  • Encapsulation

Example 4: Function Factory

Create specialized functions:

javascript
function createMultiplier(multiplier) {
    return function(number) {
        return number * multiplier;
    };
}

Example 5: Loop Closure Issue

Common mistake with var:

javascript
for (var i = 0; i < 3; i++) {
    setTimeout(function() {
        console.log(i); // All print 3!
    }, 100);
}

Problem: var is function-scoped, all closures share same i.

Solution: Use let (block-scoped):

javascript
for (let i = 0; i < 3; i++) {
    setTimeout(function() {
        console.log(i); // Prints 0, 1, 2
    }, 100);
}

When to Use:

  • Data privacy/encapsulation
  • Function factories
  • Event handlers
  • Callbacks with state
  • Module pattern

Memory Considerations:

  • Closures keep variables in memory
  • Can cause memory leaks if not careful
  • Be mindful of large objects in closures