Explain Closures in JavaScript

HighIntermediateJavascript
Quick Answer

Closures keep outer variables alive after the outer function returns. That powers private state, but the production pitfalls are loop-capture bugs, stale async state, and memory retention when callbacks keep old data alive.

Answer

The Core Idea

A closure means a function remembers variables from the place where it was created, not from where it is called. That is useful for private state and factories, but it also creates common production mistakes: async callbacks reading stale values, loop handlers capturing one shared binding, or long-lived listeners keeping old objects in memory.

JAVASCRIPT
// Simple example
function makeCounter() {
  let count = 0; // stays in memory
  return function () {
    count++;
    return count;
  };
}

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

// The inner function still 'remembers' count
                  

Why It’s Useful

Closures are powerful because they let you:

  • Keep variables private (not accessible globally)
  • Store state between function calls
  • Create helpers like once(), memoize(), and other reusable patterns
JAVASCRIPT
// Example: once()
function once(fn) {
  let called = false;
  let value;
  return function (...args) {
    if (!called) {
      called = true;
      value = fn.apply(this, args);
    }
    return value;
  };
}

const init = once(() => console.log('Initialized'));
init(); // Logs once
init(); // Does nothing — remembers state
                  

Common Mistake

Using var in loops creates one shared variable for all iterations — so all functions close over the same value:

JAVASCRIPT
const funcs = [];
for (var i = 0; i < 3; i++) {
  funcs.push(() => i);
}
console.log(funcs.map(fn => fn())); // [3, 3, 3]
                  

Fixes:

  • Use let for block scoping
  • Or use an IIFE (immediately invoked function) to capture a copy
JAVASCRIPT
// Fix with let
for (let j = 0; j < 3; j++) {
  setTimeout(() => console.log(j), 0);
}
// 0 1 2
                  

Memory Notes

Closures keep their referenced variables alive as long as the inner function exists. This can accidentally hold big objects or DOM elements in memory, so always clean up unused references.

Still so complicated?

Imagine you leave a room (outer function ends), but you gave your friend (inner function) a copy of the key to your drawer (variables). Even though you’re gone, they can still open it — that’s a closure!

Summary
  • Functions automatically form closures in JavaScript.
  • Inner functions remember outer variables (their lexical scope).
  • Used for data privacy, persistence, and modular code.
  • Use let/const to avoid loop bugs.
  • Don’t overuse closures in long-lived objects to prevent memory leaks.
Similar questions
Guides
Preparing for interviews?

Use the relevant interview-question hub first, then move into a concrete study plan before targeted company sets.