Closures in Javascript

David GostinDavid Gostin
2 min read

Closures are a fundamental concept in JavaScript, allowing functions to "remember" the environment in which they were created, even after that environment has finished executing. Here are a couple of examples that demonstrate closures in action.

Example 1: Basic Closure

In this example, an inner function retains access to the variables of its outer function, even after the outer function has completed.

function makeCounter() {
  let count = 0;

  return function() {
    count += 1;
    return count;
  };
}

const counter = makeCounter();

console.log(counter()); // Output: 1
console.log(counter()); // Output: 2
console.log(counter()); // Output: 3

Explanation

  • makeCounter defines a variable count and returns a function that increments count by 1 each time it is called.

  • When makeCounter is called, it returns the inner function, which "closes over" the count variable. Even after makeCounter has finished executing, the returned function retains access to count because of the closure.

Example 2: Closure with Parameters

Closures can also capture arguments passed to the outer function, creating a more flexible way to maintain state.

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

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

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

Explanation

  • createMultiplier takes a multiplier as an argument and returns a function that multiplies any given number by that multiplier.

  • double and triple retain the multiplier values 2 and 3, respectively, because of the closure.

  • When calling double(5) and triple(5), the returned functions remember the values passed to createMultiplier, allowing multiplier to persist.

Example 3: Private Variables Using Closures

Closures can be used to create "private" variables in JavaScript, encapsulating data within a function scope.

function BankAccount(initialBalance) {
  let balance = initialBalance;

  return {
    deposit(amount) {
      balance += amount;
      console.log(`Deposited: $${amount}. New Balance: $${balance}`);
    },
    withdraw(amount) {
      if (amount <= balance) {
        balance -= amount;
        console.log(`Withdrew: $${amount}. New Balance: $${balance}`);
      } else {
        console.log("Insufficient funds.");
      }
    },
    getBalance() {
      return balance;
    }
  };
}

const account = BankAccount(100);
account.deposit(50);      // Deposited: $50. New Balance: $150
account.withdraw(30);     // Withdrew: $30. New Balance: $120
console.log(account.getBalance()); // Output: 120

Explanation

  • BankAccount defines a private variable balance that is accessible only within the deposit, withdraw, and getBalance functions.

  • Even though BankAccount has finished executing, the returned object retains access to balance due to closures.

  • This approach simulates private variables, as balance cannot be accessed directly outside of the BankAccount function.

0
Subscribe to my newsletter

Read articles from David Gostin directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

David Gostin
David Gostin

Full-Stack Web Developer with over 25 years of professional experience. I have experience in database development using Oracle, MySQL, and PostgreSQL. I have extensive experience with API and SQL development using PHP and associated frameworks. I am skilled with git/github and CI/CD. I have a good understanding of performance optimization from the server and OS level up to the application and database level. I am skilled with Linux setup, configuration, networking and command line scripting. My frontend experience includes: HTML, CSS, Sass, JavaScript, jQuery, React, Bootstrap and Tailwind CSS. I also have experience with Amazon EC2, RDS and S3.