Tutorials Logic
Tutorials Logic, IN info@tutorialslogic.com
Navigation
Home About Us Contact Us Blogs FAQs
Tutorials
All Tutorials
Services
Academic Projects Resume Writing Website Development
Practice
Quiz Challenge Interview Questions Certification Practice
Tools
Online Compiler JSON Formatter Regex Tester CSS Unit Converter Color Picker
Compiler Tools

JavaScript Closures Explained with Examples - Interview Question

Closures

Closures are one of the most important concepts in JavaScript. A closure is created when a function remembers variables from its outer lexical scope, even after the outer function has finished executing. In simple terms, an inner function can continue to use variables declared in its parent function.

Closures exist because JavaScript uses lexical scoping. That means the scope of a variable is determined by where it is written in the code, not where the function is called from. When a function is returned or passed elsewhere, it still keeps access to the variables that were available when it was created.

Why Closures Matter

Closures are used everywhere in modern JavaScript. They help us preserve state, create private data, build reusable function factories, and write cleaner event handlers and callbacks.

  • Preserve values between function calls.
  • Create private variables without exposing them globally.
  • Build factory functions that generate customized behavior.
  • Support callbacks, timers, promises, and event listeners.
Basic Closure Example
function outerFunction() {
  const message = 'Hello from the outer function';

  function innerFunction() {
    console.log(message);
  }

  return innerFunction;
}

const fn = outerFunction();
fn(); // Hello from the outer function

In the example above, innerFunction() is returned from outerFunction(). Even though outerFunction() has already finished, innerFunction() still remembers the variable message. That remembered scope is the closure.

Closures and Private State

One of the most common uses of closures is to create private state. This is useful when you want to hide implementation details and expose only a small public API.

Private Counter
function createCounter() {
  let count = 0;

  return {
    increment() {
      count++;
      return count;
    },
    decrement() {
      count--;
      return count;
    },
    getValue() {
      return count;
    }
  };
}

const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.getValue());  // 2
console.log(counter.count);       // undefined

Here, count cannot be accessed directly from outside the function, but the returned methods still have access to it. This is a classic closure-based pattern for data privacy.

Function Factory with Closures

Closures are also useful for creating function factories. A factory function creates and returns another function with some preconfigured behavior.

Function Factory
function multiplyBy(multiplier) {
  return function(number) {
    return number * multiplier;
  };
}

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

console.log(double(5)); // 10
console.log(triple(5)); // 15

double() and triple() each preserve their own multiplier. That is why the same factory function can produce functions with different behavior.

Closures in Loops

Closures inside loops can be tricky. If you use var, every callback may end up sharing the same variable. Using let creates a new binding for each loop iteration.

Loop Closure Pitfall
// Problem with var
for (var i = 1; i <= 3; i++) {
  setTimeout(function() {
    console.log('var:', i);
  }, 100);
}

// Correct with let
for (let j = 1; j <= 3; j++) {
  setTimeout(function() {
    console.log('let:', j);
  }, 100);
}

// Output:
// var: 4
// var: 4
// var: 4
// let: 1
// let: 2
// let: 3

Real-World Uses of Closures

  • Event handlers that remember related state.
  • Debounce and throttle utilities.
  • Memoization for caching expensive computations.
  • Modules and factory functions with private configuration.
  • React hooks and callback patterns that rely on lexical scope.
Memoization Example
function memoizeSquare() {
  const cache = {};

  return function(num) {
    if (cache[num] !== undefined) {
      console.log('From cache');
      return cache[num];
    }

    console.log('Calculated');
    cache[num] = num * num;
    return cache[num];
  };
}

const square = memoizeSquare();
console.log(square(5)); // Calculated -> 25
console.log(square(5)); // From cache -> 25

Closures vs Scope

A closure is not a separate feature from scope. It is the result of normal lexical scoping plus functions being treated as first-class values. Every closure depends on scope, but not every scope usage becomes a closure. A closure happens when a function continues using outer variables after the outer function has completed.


Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.