Closures & Lexical Scope

Difficulty: Intermediate

Question

What is a closure in JavaScript? Explain with examples and real-world use cases.

Answer

A closure is a function that remembers and has access to variables from its outer (enclosing) function's scope, even after the outer function has returned. Closures are created every time a function is created.

Key points: 1. A closure gives you access to an outer function's scope from an inner function. 2. Closures are commonly used for data privacy, function factories, and partial application. 3. Variables in a closure are references (not copies), so they reflect the latest value.

Code examples

Basic Closure

function outer() {
  let count = 0;
  return function inner() {
    count++;
    return count;
  };
}

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

inner() forms a closure over 'count'. Even after outer() returns, inner() still has access to count.

Data Privacy with Closures

function createBankAccount(initialBalance) {
  let balance = initialBalance;

  return {
    deposit(amount) {
      balance += amount;
      return `Deposited ${amount}. Balance: ${balance}`;
    },
    withdraw(amount) {
      if (amount > balance) return 'Insufficient funds';
      balance -= amount;
      return `Withdrew ${amount}. Balance: ${balance}`;
    },
    getBalance() {
      return balance;
    }
  };
}

const account = createBankAccount(100);
console.log(account.deposit(50));
console.log(account.withdraw(30));
console.log(account.getBalance());

balance is private - it can only be accessed through the returned methods. This is the module pattern.

Classic Loop Problem

// Problem: all callbacks log 3
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log('var:', i), 100);
}

// Fix 1: use let (block scoping)
for (let j = 0; j < 3; j++) {
  setTimeout(() => console.log('let:', j), 200);
}

// Fix 2: use IIFE closure
for (var k = 0; k < 3; k++) {
  (function(k) {
    setTimeout(() => console.log('iife:', k), 300);
  })(k);
}

var is function-scoped, so all callbacks share the same i. let creates a new binding per iteration. IIFE captures each value.

Key points

Concepts covered

Closures, Lexical Scope, Data Privacy, Function Factory