Closures in JavaScript

A closures is a function that retains access to its lexical scope, even when it is executed outside of its original scope.

Closure remembers the varibales from the scope in which it was created, and it allowing to persist data across multiple function calls.

How Closures Work

When a function is returned from another function, it keeps a reference to the variables in its lexical scope instead of copying them. This allows it to retain data even after the other function has completed execution.

Example:

function Counter(){
    let counter = 0;

    return function increaseCounter(){
        counter++;
        console.log(`Counter : ${counter}`)
    }
}

const count = Counter();
count(); // Counter : 1
count(); // Counter : 2
count(); // Counter : 3
count(); // Counter : 4

Even though Counter() has finished execution, the returned function increaseCounter() still has access to counter because of closures.

Commonly Used Examples of Closures

  • Data Encapsulation

    Closures allow us to create private variables that cannot be accessed directly from outside a function.

    function createBankAccount(initialBalance) {
        let balance = initialBalance;
    
        return {
            deposit(amount) {
                balance += amount;
                console.log(`Deposited: ${amount}, New Balance: ${balance}`);
            },
            withdraw(amount) {
                if (amount > balance) {
                console.log("Insufficient funds");
                return;
            }
                balance -= amount;
                console.log(`Withdrew: ${amount}, Remaining Balance: ${balance}`);
            }
        };
    }
    
    const myAccount = createBankAccount(100);
    myAccount.deposit(50);  // Deposited: 50, New Balance: 150
    myAccount.withdraw(30); // Withdrew: 30, Remaining Balance: 120
    
    

    Here, balance is private and cannot be modified directly from outside.


  • Function Factories

    Closures allow us to create dynamic functions with preset values.

    function multiplier(factor) {
        return function(number) {
            return number * factor;
        };
    }
    
    const double = multiplier(2); // take factor arg
    const triple = multiplier(3); // take factor arg
    
    console.log(double(5)); // take number arg // Output: 10
    console.log(triple(5)); // take number arg // Output: 15
    

    Here, double and triple are functions that remember their factor values.


  • Memoization

    Closures helps to store previously computed results to improve performance. It used in caching the function results.

    function memoize() {
        let cache = {};
        return function(n) {
            if (n in cache) {
                console.log("Fetching from cache");
                return cache[n];
            } else {
                console.log("Calculating result");
                let result = n * n;
                cache[n] = result;
                return result;
            }
        };
    }
    
    const square = memoize();
    console.log(square(5)); // Calculating result, Output: 25
    console.log(square(5)); // Fetching from cache, Output: 25
    

  • Event Handlers in JavaScript

    Closures help manage UI state in event handlers.

    function attachEventHandlers() {
       let count = 0;
       document.getElementById("button").addEventListener("click", function() {
           count++;
           console.log(`Clicked ${count} times`);
       });
    }
    attachEventHandlers();
    

Preventing Memory Issues with Closures

While Closures are powerful, they can sometimes cause memory leaks. As we know closures keep a reference to thier outer function's scope, variables may not be freed up if they are still accessible.

Preventing Memory Issues with Closures

  • If a closure is no longer needed, setting variables to null can help release memory.
  • We can use WeakMap or WeakSet for storing large objects, because WeakMap and WeakSet hold "weak" references, which means if an object is no longer referenced anywhere else, it will be automatically garbage collected.