Skip to content

JavaScript Tutorial Functions

JavaScript Closures

Lesson 60 of 258 2 min read By Deepak Paswan Updated Oct 4, 2026

A closure is a function that remembers the variables from the place where it was created, even after that place has finished running.

That sounds odd, so here is a real example. Imagine a counter that keeps its own count.

script.js
JS
function makeCounter() {
  let count = 0;

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

const counter = makeCounter();
console.log(counter()); // → 1
console.log(counter()); // → 2
console.log(counter()); // → 3

What is going on?

  1. makeCounter() creates a variable count and returns an inner function.
  2. makeCounter has finished. Normally count would disappear.
  3. But the inner function still refers to count, so JavaScript keeps it alive for that function.

The inner function “closed over” count. Nobody else can reach it: there is no way to set count except by calling counter(). That makes closures a way to create private data.

Each closure has its own copy

script.js
JS
const a = makeCounter();
const b = makeCounter();

console.log(a(), a(), b()); // → 1 2 1

function makeCounter() {
  let count = 0;
  return () => ++count;
}

a and b do not interfere. Each call to makeCounter() creates a fresh count.

A practical use: remembering a setting

script.js
JS
function makeGreeter(greeting) {
  return function (name) {
    return `${greeting}, ${name}!`;
  };
}

const sayHello = makeGreeter("Hello");
const sayHola = makeGreeter("Hola");

console.log(sayHello("Maya")); // → Hello, Maya!
console.log(sayHola("Maya"));  // → Hola, Maya!

Closures in event handlers

Closures are why a click handler can use variables from where it was created:

index.html
HTML
<button id="add">Add</button>
<p id="total">0</p>
<script>
  let total = 0;                       // lives on after this code finishes
  document.querySelector("#add").addEventListener("click", () => {
    total += 1;                        // the handler remembers `total`
    document.querySelector("#total").textContent = total;
  });
</script>

Closures and loops

The classic var bug from var and Hoisting is a closure problem: all callbacks shared one i. With let, each round creates a new variable, so each callback gets its own.

info
You use closures already
Any function that uses a variable from outside itself is a closure, including every callback in this course. You do not have to “do” anything to get one. Understanding them just explains behaviour that would otherwise look like magic.