Closures in JavaScript

Introduction

A closure is when a function remembers variables from the scope where it was created—even after that outer function has finished. Closures power private state, factories, and callbacks. They are one of the most important ideas in JavaScript for intermediate developers.

Prerequisites

Inner Function Sees Outer Variables

javascript
// Outer variable still visible inside inner
function outer() {
  const message = "hello from outer";
 
  function inner() {
    console.log(message);
  }
 
  return inner;
}
 
const fn = outer();
fn();

inner closes over message.

Counter with Private State

javascript
// Factory hiding count
function createCounter(start = 0) {
  let count = start;
 
  return {
    increment() {
      count += 1;
      return count;
    },
    get() {
      return count;
    },
  };
}
 
const c = createCounter(10);
c.increment();
console.log(c.get());

count is not exported—only methods access it.

Closures in Loops (Historical Pitfall)

With var, every timeout shared one i. With let, each iteration gets its own binding:

javascript
// let creates per-iteration binding
for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 10 * i);
}

Function Returning Function

javascript
// multiplyBy returns specialized multiplier
function multiplyBy(factor) {
  return (n) => n * factor;
}
 
const double = multiplyBy(2);
const triple = multiplyBy(3);
 
console.log(double(5));
console.log(triple(5));

Memory Note

Closures keep outer variables alive while the inner function is reachable—avoid accidental retention of huge objects in long-lived callbacks.

Mini Example: Rate Limiter Stub

javascript
// Only allow call once per windowMs
function oncePer(windowMs, fn) {
  let last = 0;
  return (...args) => {
    const now = Date.now();
    if (now - last < windowMs) return;
    last = now;
    return fn(...args);
  };
}
 
const save = oncePer(1000, () => console.log("saved"));
save();
save();

FAQ

Is closure a special syntax?

No—it is behavior: inner function + referenced outer variables.

Can closures cause bugs?

Yes—stale values in async code or memory leaks if closures hold large graphs.

Same as scope chain?

Related—closure is the practical effect of lexical scope plus live bindings.

What comes next?

Callbacks and higher-order functions.