One of the most frequently asked JavaScript interview questions is:

What is a closure in JavaScript?

Many developers memorize the definition:

"A closure is a function bundled together with its lexical environment."

While technically correct, interviewers usually want to know:

  • Why closures exist
  • How closures work internally
  • Where closures are used in real applications
  • Common closure pitfalls
  • How closures relate to scope and memory

Let's understand closures from first principles.

1. What Problem Do Closures Solve?#

Consider this example:

JAVASCRIPT
function greet() {
  const name = "John";

  console.log(name);
}

greet();

Output:

John

After the function finishes:

Execution Context Removed

Normally, local variables disappear.

Now imagine we want access to those variables later.

Closures make this possible.

2. What is a Closure?#

A closure is created when a function remembers variables from its outer scope even after that outer function has finished executing.

Example:

JAVASCRIPT
function outer() {
  const name = "John";

  function inner() {
    console.log(name);
  }

  return inner;
}

const greet = outer();

greet();

Output:

John

Important observation:

outer() already finished executing

Yet:

JAVASCRIPT
inner();

still accesses:

JAVASCRIPT
name;

This is a closure.

Why Does This Work?#

When JavaScript creates a function, it stores:

Function Code
+
Reference To Outer Scope

Conceptually:

inner
 ↓
Lexical Environment
 ↓
name = "John"

Even after:

JAVASCRIPT
outer();

finishes execution, JavaScript keeps the referenced variables alive because the returned function still needs them.

3. Lexical Scope vs. Closure#

These terms are often confused.

Lexical Scope#

Determines where variables can be accessed.

Example:

JAVASCRIPT
function outer() {
  const name = "John";

  function inner() {
    console.log(name);
  }
}

Because:

JAVASCRIPT
inner;

is written inside:

JAVASCRIPT
outer;

it can access:

JAVASCRIPT
name;

This is lexical scope.

Closure#

When a function continues accessing those variables after the outer function has completed execution.

Example:

JAVASCRIPT
const fn = outer();

fn();

This is a closure.

Visual Representation#

outer()
 ├── name = "John"
 └── returns inner()

inner()
 ↓
Remembers
 ↓
name = "John"

Closure Interview Example#

JAVASCRIPT
function createCounter() {
  let count = 0;

  return function () {
    count++;

    console.log(count);
  };
}

const counter = createCounter();

counter();
counter();
counter();

Output:

1
2
3

Why?

Because:

JAVASCRIPT
count;

remains available through the closure.

4. Encapsulation: Private Variables#

Closures are commonly used for data encapsulation.

Example:

JAVASCRIPT
function createBankAccount() {
  let balance = 1000;

  return {
    deposit(amount) {
      balance += amount;
    },

    getBalance() {
      return balance;
    },
  };
}

Usage:

JAVASCRIPT
const account = createBankAccount();

account.deposit(500);

console.log(account.getBalance());

Output:

1500

But:

JAVASCRIPT
console.log(account.balance);

Output:

undefined

The variable remains private.

5. Real-World Use Cases (Event Handlers & Debounce)#

Closures are everywhere in frontend development.

Example:

JAVASCRIPT
function setupButton(buttonId) {
  const id = buttonId;

  document.getElementById(id).addEventListener("click", () => {
    console.log(id);
  });
}

The event handler remembers:

JAVASCRIPT
id;

through a closure.

Real Frontend Example: Debounce#

JAVASCRIPT
function debounce(fn, delay) {
  let timer;

  return function (...args) {
    clearTimeout(timer);

    timer = setTimeout(() => {
      fn(...args);
    }, delay);
  };
}

Why does debounce work?

Because the returned function remembers:

JAVASCRIPT
timer;

via a closure.

Real Frontend Example: React Hooks#

Consider:

JSX
function Counter() {
  const [count, setCount] = useState(0);

  function handleClick() {
    console.log(count);
  }

  return <button onClick={handleClick}>Click</button>;
}

The event handler has access to:

JAVASCRIPT
count;

through closures.

React relies heavily on closure behavior.

Common Interview Question#

What is the output?

JAVASCRIPT
function outer() {
  let count = 0;

  return function () {
    count++;
    console.log(count);
  };
}

const fn1 = outer();
const fn2 = outer();

fn1();
fn1();
fn2();

Answer#

Output:

1
2
1

Why?

Each call to:

JAVASCRIPT
outer();

creates a new closure.

fn1 → count
fn2 → count

Separate memory.

6. Classic Interview Trap: Loop & Var#

What is the output?

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

Answer#

Output:

3
3
3

Why?

All callbacks share the same variable:

JAVASCRIPT
i;

By the time the callbacks execute:

JAVASCRIPT
i === 3;

Fix Using let#

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

Output:

0
1
2

Because:

JAVASCRIPT
let;

creates a new binding for each iteration.

Fix Using Closure#

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

Output:

0
1
2

The closure preserves each value.

7. Closures and Memory Management#

A common senior-level interview question:

Can closures cause memory leaks?

Answer:

Yes

Closures keep references alive.

Example:

JAVASCRIPT
function hugeData() {
  const data = new Array(1000000);

  return function () {
    console.log(data.length);
  };
}

As long as the returned function exists:

JAVASCRIPT
data;

cannot be garbage collected.

When Are Closures Created?#

Closures are created:

At Function Creation Time

not when the function executes.

Example:

JAVASCRIPT
function outer() {
  const name = "John";

  return function inner() {
    console.log(name);
  };
}

When:

JAVASCRIPT
inner;

is created, JavaScript captures its lexical environment.

8. Common Interview Q&A#

Do Closures Copy Variables?#

No.

Closures maintain references to variables.

Example:

JAVASCRIPT
function outer() {
  let count = 0;

  return {
    increment() {
      count++;
    },

    getCount() {
      return count;
    },
  };
}

Both functions access the same variable.

Are Closures Only Created When Returning Functions?#

No.

Closures occur whenever a function accesses variables from an outer scope.

Example:

JAVASCRIPT
function outer() {
  const name = "John";

  function inner() {
    console.log(name);
  }

  inner();
}

A closure still exists.

Why Are Closures Useful?#

Closures enable:

  • Data privacy
  • Function factories
  • Event handlers
  • Debouncing
  • Throttling
  • Memoization
  • React Hooks

Can Closures Access Global Variables?#

Yes.

Example:

JAVASCRIPT
const company = "FrontendPrep";

function greet() {
  console.log(company);
}

The closure includes references to outer scopes.

Function Factory Example#

Closures are commonly used to generate customized functions.

JAVASCRIPT
function multiply(multiplier) {
  return function (number) {
    return number * multiplier;
  };
}

const double = multiply(2);
const triple = multiply(3);

Usage:

JAVASCRIPT
double(5);

Output:

10

Usage:

JAVASCRIPT
triple(5);

Output:

15

Each function has its own closure.

Senior-Level Interview Answer#

A closure is formed when a function retains access to variables from its lexical scope even after the outer function has completed execution. JavaScript functions capture references to their surrounding environment at creation time, allowing those variables to remain accessible later. Closures power many important JavaScript patterns including data encapsulation, event handlers, debouncing, throttling, memoization, and React Hooks. While closures are extremely useful, they can also increase memory usage because referenced variables cannot be garbage collected until all closures referencing them are removed.

Common Interview Mistakes#

❌ "Closures copy variables."

Correct:

Closures keep references to variables.

❌ "Closures only happen when functions are returned."

Correct:

Closures occur whenever a function accesses an outer scope.

❌ "Closures are a feature."

Correct:

Closures are a natural consequence of lexical scoping.

❌ "Closures are only used in advanced JavaScript."

Correct:

Closures are used constantly in modern frontend development.

Key Takeaways#

  • Closure Mechanics: A function's ability to remember and access its lexical outer scope even when executed outside that scope.
  • Encapsulation: Used in JavaScript to create private variables and hide internal component logic.
  • Lexical Scope: Scope is determined at compile time based on where functions are declared in the codebase.
  • Loop Variables: Classical closure trap where var in a loop shares a single binding; solved using block-scoped let.
  • Memory Overhead: Variables held in closures are not garbage-collected as long as the inner function reference persists.