DEV Community

Cathy Lai
Cathy Lai

Posted on

Closures

What is a closure?

A closure happens when a function “remembers” the variables from the scope where it was created, even after that scope has finished running.

In other words:

👉 A function carries around a backpack of variables from the place it was born.


1. Simple example

function outer() { const message = "Hello from outer!"; function inner() { console.log(message); // uses variable from outer scope } return inner; } const fn = outer(); fn(); // "Hello from outer!" 
Enter fullscreen mode Exit fullscreen mode
  • inner is returned out of outer.
  • Even though outer has finished, inner still has access to message.
  • That’s the closureinner “closes over” the message variable.

2. Closure with parameters

function makeMultiplier(multiplier) { return function (x) { return x * multiplier; }; } const double = makeMultiplier(2); console.log(double(5)); // 10 const triple = makeMultiplier(3); console.log(triple(5)); // 15 
Enter fullscreen mode Exit fullscreen mode
  • double remembers multiplier = 2.
  • triple remembers multiplier = 3.
  • Each returned function has its own closure environment.

3. In React hooks

Closures explain why we can do this:

const greeting = useMemo(() => { return `Hello, ${name}`; }, [name]); 
Enter fullscreen mode Exit fullscreen mode
  • The () => { ... } factory closes over the current value of name.
  • React doesn’t pass name into the function — the closure makes it available.
  • That’s why we must put name in the dependency array, so React knows when the closed-over value might change.

4. Analogy 🎒

Imagine a function is a traveler.

  • When it’s created, it packs a backpack with the variables in scope.
  • Later, no matter where it goes, it can unzip the backpack and use those variables.

Java vs JavaScript analogy

Java local variables

In Java:

void outer() { String message = "Hello"; class Inner { void print() { System.out.println(message); } } Inner i = new Inner(); i.print(); // prints "Hello" } 
Enter fullscreen mode Exit fullscreen mode
  • message is a local variable of outer().
  • Inner classes in Java can “capture” these variables, but Java enforces them to be effectively final (not reassigned after creation). So inner classes in Java have a limited version of closure.

JavaScript closures

In JS:

function outer() { let message = "Hello"; function inner() { console.log(message); } return inner; } const fn = outer(); fn(); // "Hello" 
Enter fullscreen mode Exit fullscreen mode
  • message is a local variable of outer().
  • inner keeps a live reference to message even after outer has finished.
  • Unlike Java, JavaScript allows closures over variables that can change:
function outer() { let count = 0; return function() { count++; return count; }; } const inc = outer(); console.log(inc()); // 1 console.log(inc()); // 2 console.log(inc()); // 3 
Enter fullscreen mode Exit fullscreen mode

Here count behaves like private state — accessible only through the closure.


Key difference

  • Java local variables (in lambdas/inner classes) → captured by value, must be effectively final.
  • JavaScript closures → captured by reference, can update over time, and the function “remembers” the variable for as long as it’s alive.

Analogy

  • In Java: closure = you take a snapshot of a local variable at the time the inner class/lambda was created.
  • In JS: closure = you keep a live wire to the variable itself — if it changes later, your function sees the updated value.

✅ So closure variables look like local variables in Java, but in JavaScript they are kept alive and mutable by the function that closes over them.

Top comments (0)