I am online
← Back to Articles

Understanding JavaScript Closures: A Complete Guide

JavaScriptJuly 13, 2026

Introduction

Closures are one of the most powerful and frequently asked JavaScript concepts in interviews. They allow functions to "remember" variables from their outer scope, even after that outer function has finished executing.

Once you understand closures, you'll better understand callbacks, event listeners, React hooks, private variables, and many JavaScript patterns.

What Is a Closure?

A closure is a function that has access to variables from its outer lexical scope, even after the outer function has returned.

Example:

function greet(name) {
  return function () {
    console.log(`Hello ${name}`);
  };
}

const sayHello = greet("Yacine");

sayHello();

Output:

Hello Yacine

Although greet() has already finished executing, the inner function still remembers the value of name.

Lexical Scope

Closures are possible because JavaScript uses lexical scope.

const message = "Hello";

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

sayHello();

Output:

Hello

Functions can access variables declared in their parent scope.

A Simple Closure Example

function counter() {
  let count = 0;

  return function () {
    count++;
    return count;
  };
}

const increment = counter();

console.log(increment());
console.log(increment());
console.log(increment());

Output:

1
2
3

The variable count is preserved between function calls.

Private Variables

Closures allow you to create private state.

function createUser(name) {
  let balance = 0;

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

    getBalance() {
      return balance;
    },

    getName() {
      return name;
    },
  };
}

const user = createUser("Alice");

user.deposit(100);

console.log(user.getBalance());

Output:

100

The balance variable cannot be accessed directly.

Closures with Event Listeners

function createButton(message) {
  return function () {
    alert(message);
  };
}

button.addEventListener("click", createButton("Welcome!"));

Each event handler remembers its own message.

Closures in Loops

Incorrect:

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

Output:

4
4
4

Correct:

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

Output:

1
2
3

let creates a new binding for each iteration.

Function Factory

Closures make it easy to generate specialized functions.

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

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

console.log(double(10));
console.log(triple(10));

Output:

20
30

Closures in React

Closures are everywhere in React.

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

  function increment() {
    setCount(count + 1);
  }

  return (
    <button onClick={increment}>
      {count}
    </button>
  );
}

The increment function closes over the current count value.

Common Use Cases

Closures are commonly used for:

  • Data privacy
  • Event handlers
  • Callbacks
  • Timers
  • Function factories
  • Memoization
  • React Hooks
  • Custom hooks
  • Module patterns

Common Mistakes

Forgetting closures keep references

function test() {
  let value = 1;

  return () => value;
}

The closure doesn't copy the variable—it keeps a reference to it.

Memory leaks

Closures can unintentionally keep large objects in memory if they are no longer needed.

function largeData() {
  const items = new Array(1000000).fill("data");

  return () => items.length;
}

Avoid retaining unnecessary references.

Best Practices

  • Use closures for encapsulation.
  • Keep captured variables small.
  • Prefer let and const over var.
  • Avoid unnecessary nested functions.
  • Be mindful of memory usage.
  • Use closures intentionally, not everywhere.

Closures are a fundamental feature of JavaScript. They allow functions to retain access to variables from their lexical scope, enabling powerful patterns like private state, callbacks, event handlers, and function factories.

Whether you're building applications with JavaScript, React, Next.js, or Node.js, understanding closures will help you write cleaner, more maintainable, and more predictable code.