JavaScript Closures Explained (With Interview Questions)

Closures in plain English: lexical scope, how closures work, common interview traps (loops + setTimeout), and practical use cases like memoization and data hiding.

F

Frontend Interview Team

February 08, 2026

~12 min
JavaScript Closures Explained (With Interview Questions)

A closure is one of those interview topics that sounds scary until you realize it’s just this:

A function “remembers” the variables from the place it was created.

30‑second interview answer

A closure is created when a function is defined inside another scope and references variables from that outer scope. Even after the outer function finishes, the inner function can still access those variables because JavaScript keeps the lexical environment alive as long as it’s reachable.

Key points

  • Closures come from lexical scope, not async.
  • Closures preserve access to variables (not necessarily copying values).
  • They’re used for private state, factories, memoization, and event handlers.

That place is called lexical scope.


1) The smallest closure example

function outer() {
  const name = 'Rajesh';
 
  function inner() {
    console.log(name);
  }
 
  return inner;
}
 
const fn = outer();
fn(); // Rajesh

Even though outer() finished, inner() still has access to name.

That’s the closure.


2) What closures are NOT

Closures are not:

  • a special syntax
  • only for async
  • only for React hooks

Closures happen because of:

  • lexical scoping (scope is decided by where code is written)
  • functions being first-class values

3) Interview question: “Why does this print 3,3,3?”

for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 0);
}

Explanation

  • var is function-scoped (not block-scoped).
  • All callbacks close over the same i.
  • By the time the timeouts run, i is 3.

Fix #1: use let

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

Because let creates a new binding per loop iteration.

Fix #2: IIFE (older pattern)

for (var i = 0; i < 3; i++) {
  (function (x) {
    setTimeout(() => console.log(x), 0);
  })(i);
}

4) Practical use cases (what interviewers like)

A) Data hiding / private state

function createCounter() {
  let count = 0;
 
  return {
    inc() { count++; return count; },
    dec() { count--; return count; },
    get() { return count; }
  };
}
 
const c = createCounter();
c.inc(); // 1
c.get(); // 1

Here, count is private. Only the returned methods can access it.

B) Memoization (cache results)

function memoize(fn) {
  const cache = new Map();
 
  return function (...args) {
    const key = JSON.stringify(args);
    if (cache.has(key)) return cache.get(key);
 
    const result = fn(...args);
    cache.set(key, result);
    return result;
  };
}

C) Function factories

function multiplyBy(n) {
  return function (x) {
    return x * n;
  };
}
 
const double = multiplyBy(2);
double(10); // 20

5) Common closure bug in React

In React, closures often show up as “stale state”.

Example pattern:

  • you use a value inside an effect
  • but your dependency array doesn’t include it

Then your function closes over an old value.

(We’ll cover this properly in the React hooks section.)


6) Rapid-fire interview Q&A

Q1: What is a closure?

  • A function + its lexical environment (the variables it can access).

Q2: When is a closure created?

  • When a function is defined inside another scope and references outer variables.

Q3: Does closure mean the variables are copied?

  • No, usually it keeps a reference to the environment.

Q4: Is closure only for async?

  • No. Async just makes it more visible.

Q5: Can closures cause memory leaks?

  • Yes, if you keep references to large objects longer than needed.

Summary checklist

  • I can define closure in one sentence.
  • I can explain the for loop + setTimeout trap.
  • I can give 2 real-world use cases (private state, memoization, factories).
  • I know closures can keep memory alive if references persist.

Summary

  • Closures = functions remembering outer variables.
  • let fixes most loop closure issues.
  • Interviewers love when you connect closures to real use cases: private state, memoization, factories.