Closures and the Scope Chain: Real-World Examples
Closures are used everywhere: event handlers, memoization, currying, data privacy. Here are real examples.
Closures and the Scope Chain: Real-World Examples
Closures are not just an interview topic. They are used in real code every day. Here are practical examples.
Example 1: Data Privacy
function createBankAccount() { let balance = 0; return { deposit(amount) { balance += amount; }, withdraw(amount) { balance -= amount; }, getBalance() { return balance; }, }; } const acc = createBankAccount(); acc.deposit(100); acc.getBalance(); // 100 // balance is not accessible directly `` `balance` is private. It can only be accessed through the returned methods. This is the module pattern. ### Example 2: Memoization ```js function memoize(fn) { const cache = {}; return (...args) => { const key = JSON.stringify(args); if (cache[key]) return cache[key]; cache[key] = fn(...args); return cache[key]; }; } const slowFib = memoize((n) => n < 2 ? n : slowFib(n - 1) + slowFib(n - 2)); `` `cache` is closed over. Each call to the returned function checks and updates the cache without exposing it. ### Example 3: Currying and Partial Application ```js function curry(fn) { return function curried(...args) { if (args.length >= fn.length) return fn(...args); return (...next) => curried(...args, ...next); }; } const sum = curry((a, b, c) => a + b + c); sum(1)(2)(3); // 6 `` Each partial call closes over the accumulated `args`. ### Example 4: Event Handlers ```js function setupCounter(button) { let count = 0; button.addEventListener("click", () => { count++; button.textContent = `Clicked ${count}`; }); } `` The handler closes over `count` and `button`. Each click increments the closed-over `count`. ### Example 5: Once Utility ```js function once(fn) { let done = false; let result; return (...args) => { if (done) return result; done = true; result = fn(...args); return result; }; } const init = once(() => { console.log("initializing"); return 42; }); init(); // logs "initializing", returns 42 init(); // returns 42 without logging `` `done` and `result` are closed over, so the function only runs once. ### Example 6: Loop With `let` ```js for (let i = 0; i < 3; i++) { setTimeout(() => console.log(i), 0); } // logs 0, 1, 2 `` `let` creates a fresh binding per iteration. Each callback closes over its own `i`. This is closures + block scope working together. ### The Takeaway Closures power data privacy, memoization, currying, event handlers, once-utilities, and the `let` loop fix. Anywhere you need a function to remember variables from where it was written, you are using closures.
By declaring a variable inside a function and returning methods that access it. The variable is not accessible directly from outside, only through the returned methods. This is the module pattern.
The memoize function closes over a cache object. The returned function checks and updates the cache without exposing it. Each call returns the cached result if available, otherwise computes and stores it.
Because let creates a fresh binding per iteration. Each callback closes over its own copy of i, so they log 0, 1, 2. With var, all callbacks share one i, so they all log the final value.
It closes over a done flag and a result variable. The first call sets done to true and stores the result. Subsequent calls return the stored result without running the function again.
A handler defined inside a setup function closes over the local variables (like a count or an element reference). Each event fires the handler, which can read and update those closed-over variables.
Ready to master React completely?
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.
Master React
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course.

