10+ JavaScript Closures Interview Questions 2025: Scope, Memory & Loop Problems

·7 min read
javascriptinterview-questionsclosuresfrontendscopefunctions

Closures power React hooks, enable private variables, and appear in nearly every JavaScript technical interview. They're so fundamental that they're built into the language itself—yet most candidates either over-explain them or can't give a practical example.

Table of Contents

  1. Closure Fundamentals Questions
  2. Scope and Lexical Environment Questions
  3. Loop and Async Questions
  4. Practical Applications Questions
  5. Memory and Performance Questions
  6. Quick Reference

Closure Fundamentals Questions

These questions test your core understanding of what closures are and how they work.

What is a closure in JavaScript?

A closure is a function that remembers the variables from its outer scope, even after the outer function has finished executing. When you create a function inside another function, the inner function has access to its own variables, the outer function's variables, and global variables.

What makes closures special is that this access persists even after the outer function returns. The inner function "closes over" those variables, keeping them alive in memory.

How do you demonstrate a closure with a simple example?

The counter example is the classic demonstration of closures in action:

function createCounter() {
  let count = 0;  // This variable is "closed over"
 
  return function() {
    count++;
    return count;
  };
}
 
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3

Even though createCounter has finished executing, the returned function still has access to count. Each call increments the same count variable because the inner function maintains a reference to its outer scope.


Scope and Lexical Environment Questions

These questions test your understanding of how closures relate to JavaScript's scoping rules.

How do closures relate to lexical scope?

Closures are a direct result of lexical scoping in JavaScript. Lexical scope means a function's scope is determined by where it's written in the code, not where it's called. Closures leverage this by allowing inner functions to access outer variables based on where they were defined.

The inner function "remembers" its lexical environment even when executed outside of it. This is why a function returned from another function can still access the outer function's variables.

What are the three scopes a nested function can access?

When you create a function inside another function, the inner function has access to three scopes: its own local variables, the outer (enclosing) function's variables, and global variables. This chain of accessible scopes is called the scope chain.

const globalVar = 'global';
 
function outer() {
  const outerVar = 'outer';
 
  function inner() {
    const innerVar = 'inner';
    console.log(innerVar);  // inner's own scope
    console.log(outerVar);  // outer function's scope
    console.log(globalVar); // global scope
  }
 
  return inner;
}

Loop and Async Questions

These questions test your understanding of the classic closure pitfall with loops and asynchronous code.

Why does the classic for loop with setTimeout print the same number?

When using var in a for loop with setTimeout, all callbacks share the same variable reference. By the time the callbacks execute, the loop has finished and the variable holds its final value.

for (var i = 0; i < 3; i++) {
  setTimeout(function() {
    console.log(i);
  }, 1000);
}
// Output: 3, 3, 3 (not 0, 1, 2)

This happens because var is function-scoped, not block-scoped. All three callback functions close over the same i variable, and when they finally execute after 1 second, i has already been incremented to 3.

How do you fix the loop closure problem using let?

Using let instead of var creates a new binding for each iteration, so each callback closes over its own copy of the variable.

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

How do you fix the loop closure problem using an IIFE?

An Immediately Invoked Function Expression (IIFE) captures the current value of i by passing it as a parameter, creating a new scope for each iteration.

for (var i = 0; i < 3; i++) {
  (function(j) {
    setTimeout(function() {
      console.log(j);
    }, 1000);
  })(i);
}
// Output: 0, 1, 2

The IIFE creates a new function scope that captures i as j for each iteration. This was the standard solution before let was introduced in ES6.

How do you fix the loop closure problem using forEach?

Using forEach instead of a traditional for loop creates a new scope for each callback, solving the closure problem naturally.

[0, 1, 2].forEach(function(i) {
  setTimeout(function() {
    console.log(i);
  }, 1000);
});
// Output: 0, 1, 2

Practical Applications Questions

These questions test your knowledge of real-world closure use cases.

How do you create private variables using closures?

Closures enable data privacy by keeping variables inaccessible from outside the function. You define a variable inside a function and return methods that can access it, but external code cannot access the variable directly.

function createBankAccount(initialBalance) {
  let balance = initialBalance; // Private variable
 
  return {
    deposit: function(amount) {
      balance += amount;
      return balance;
    },
    getBalance: function() {
      return balance;
    }
  };
}
 
const account = createBankAccount(100);
account.deposit(50);     // 150
account.getBalance();    // 150
// account.balance       // undefined - can't access directly!

What is a function factory and how does it use closures?

A function factory is a function that creates and returns other functions, using closures to "bake in" certain values. Each returned function remembers the values from when it was created.

function multiply(x) {
  return function(y) {
    return x * y;
  };
}
 
const double = multiply(2);
const triple = multiply(3);
 
double(5);  // 10
triple(5);  // 15

How do closures work with event handlers?

Event handlers frequently use closures to maintain access to variables from their enclosing scope. This allows you to configure event behavior at setup time while the handler executes later.

function setupButton(buttonId, message) {
  document.getElementById(buttonId).addEventListener('click', function() {
    alert(message); // message is closed over
  });
}

The callback function closes over message, so it remembers the value even though setupButton has already returned when the click happens.


Memory and Performance Questions

These questions test your understanding of the tradeoffs when using closures.

What are the downsides of using closures?

Closures have three potential downsides. First, closed-over variables stay in memory as long as the closure exists, which increases memory usage. Second, if closures reference large objects or DOM elements, those won't be garbage collected until the closure is released, potentially causing memory leaks. Third, debugging can be harder when tracking variable values across multiple scopes.

When should you avoid using closures?

Avoid closures when you're creating many instances in a loop and each closure holds references to large objects. Also be cautious when closures reference DOM elements that may be removed—the closure prevents garbage collection. In performance-critical code, unnecessary closures add overhead compared to simple function calls.

How do you prevent memory leaks with closures?

To prevent memory leaks, set closure references to null when no longer needed, especially for event handlers on DOM elements that get removed. Use weak references where appropriate, and be mindful of what variables the closure actually needs—avoid closing over entire objects when you only need one property.


Quick Reference

ConceptKey Points
What is a closure?Function + its lexical environment
Why use closures?Data privacy, factories, callbacks
Loop problem causevar shares scope across iterations
Loop problem fixUse let, IIFE, or forEach
Memory concernClosed variables stay in memory
Lexical scopeScope determined by code location

Ready to ace your interview?

Get 550+ interview questions with detailed answers in our comprehensive PDF guides.

View PDF Guides