Back to Blog
Fundamentals2026-04-27

JavaScript Closures: Real-World Examples

Closures are not just an interview question. Here are patterns you actually ship.

A closure is a function plus its lexical scope. The interview answer ends there. The useful part starts with how teams actually use them.

Private State Without Classes

``js function createCounter() { let count = 0; return { increment() { count++; }, get() { return count; } }; } `

The count variable is unreachable from outside — true encapsulation, no #private syntax needed.

Memoization

`js function memoize(fn) { const cache = new Map(); return (...args) => { const key = JSON.stringify(args); if (!cache.has(key)) cache.set(key, fn(...args)); return cache.get(key); }; } `

The cache survives between calls because it lives in the closure.

Event Handler with Captured Context

`js function attachAnalytics(buttonEl, eventName) { buttonEl.addEventListener('click', () => track(eventName)); } `

Each handler remembers its own eventName without globals.

Module Pattern

Before ES modules, the module pattern used closures to namespace:

`js const Logger = (() => { let level = 'info'; return { setLevel(l) { level = l; }, log(msg) { if (priority(level)) console.log(msg); } }; })(); `

The for-loop var Trap

`js for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 0); // 3, 3, 3 } for (let i = 0; i < 3; i++) { setTimeout(() => console.log(i), 0); // 0, 1, 2 } `

let` creates a new binding per iteration, fixing the classic closure-over-loop-variable bug.

Closures power most utility libraries. Pair them with [destructuring tricks](/blog/destructuring-tricks) for cleaner factory functions.