JavaScript Closures

(Functions remembering their outer scope — even after the outer function has finished)


What is a Closure?

A closure is formed when a function "remembers" the variables from its outer (lexical) scope, even after the outer function has returned.

Basic Concept

function outer() {
  let name = "Alice";
                                
  function inner() {
    console.log("Hello, " + name); // name comes from outer()
  }
                                
  return inner;
}
                                
const greet = outer(); // outer() returns inner
greet(); // "Hello, Alice"

Even though outer() has finished executing, inner() still remembers name because of closure.

Why Closures Are Useful

Closures are used in:

  • Data privacy (encapsulation)
  • Function factories (customized functions)
  • Maintaining state in async operations
  • React hooks like useState, useEffect

Closure for Data Privacy

function secretHolder() {
  let secret = "1234";
                                
  return {
    getSecret: function () {
      return secret;
    },
    setSecret: function (newSecret) {
      secret = newSecret;
    },
  };
}
                                
const vault = secretHolder();
console.log(vault.getSecret()); // "1234"
vault.setSecret("5678");
console.log(vault.getSecret()); // "5678"

secret can't be accessed directly — only through the returned methods.

Closure in Loop Problem (var vs let)

for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 1000);
}
// Output: 3 3 3 (Not 0 1 2!)

Fix with let:

for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 1000);
}
// Output: 0 1 2 ✅

Explanation: let creates a new block scope per iteration, so each i is preserved properly due to closure.

Function Factory (Function that creates other functions)

function makeMultiplier(x) {
  return function (y) {
    return x * y;
  };
}
                                  
const double = makeMultiplier(2);
console.log(double(5)); // 10
                                  
const triple = makeMultiplier(3);
console.log(triple(5)); // 15

Each returned function "remembers" its own value of x.

Summary

  • A closure gives you access to an outer function’s variables from an inner function.
  • Closures preserve state across calls and enable private variables.
  • Common in JavaScript features like event handlers, timeouts, and module patterns.

🧪 Practice Exercise:

Task:

  1. Create a counter() function that returns a function that increments and logs the count.
  2. Build a greeting(name) function that returns another function saying "Hello, name".
  3. Use closure to protect a secret password (get/set it only through methods).
  4. Write a function that returns a multiplier function using closure.
  5. Explain in comments why a closure retains access to outer variables.