Closure
🔹 What is a Closure?
A closure is created when a function remembers the variables from its outer scope even after that outer function has finished executing.
👉 In simple words:
Inner functions can access variables of their outer function even after the outer function has returned.
Example 1: Basic Closure
function outer() {
let count = 0; // outer variable
function inner() {
count++; // inner function using outer variable
return count;
}
return inner;
}
const counter = outer();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
✅ Even though outer() finished executing, the inner() function still remembers count.
That’s a closure!
🔹 Why Closures are Useful?
Data privacy (variables hidden from outside)
Stateful functions (functions that “remember” things)
Callbacks & Event Listeners
Module pattern (imitating private methods in JS)
🔹 10 Problems on Closures (with Solutions)
Problem 1: Counter Function
Create a function that counts how many times it has been called.
function createCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
Problem 2: Private Variable
Make a variable private so it cannot be accessed directly.
function secretHolder(secret) {
return {
getSecret: function() {
return secret;
},
setSecret: function(newSecret) {
secret = newSecret;
}
};
}
const holder = secretHolder("abc123");
console.log(holder.getSecret()); // abc123
holder.setSecret("newSecret");
console.log(holder.getSecret()); // newSecret
Problem 3: Multiplication Factory
Make a function that returns another function which multiplies numbers.
function multiplier(x) {
return function(y) {
return x * y;
};
}
const double = multiplier(2);
console.log(double(5)); // 10
const triple = multiplier(3);
console.log(triple(5)); // 15
Problem 4: Remember Me
Create a function that remembers a name.
function rememberName(name) {
return function() {
return "Hello, " + name;
};
}
const greetAmit = rememberName("Amit");
console.log(greetAmit()); // Hello, Amit
Problem 5: Event Listener with Closure
Closures allow us to remember data inside event listeners.
function attachEvent() {
let count = 0;
document.getElementById("btn").addEventListener("click", function() {
count++;
console.log("Button clicked " + count + " times");
});
}
attachEvent();
Problem 6: Delay Logger
Print numbers 1 to 5 with setTimeout.
❌ Common mistake:
for (var i = 1; i <= 5; i++) {
setTimeout(() => console.log(i), 1000);
}
// Prints 6 five times
✅ Solution using closure:
for (var i = 1; i <= 5; i++) {
(function(n) {
setTimeout(() => console.log(n), 1000 * n);
})(i);
}
// Prints 1, 2, 3, 4, 5
Problem 7: Create ID Generator
Every time you call, you get a new ID.
function idGenerator() {
let id = 0;
return function() {
id++;
return "ID-" + id;
};
}
const generate = idGenerator();
console.log(generate()); // ID-1
console.log(generate()); // ID-2
Problem 8: Only Once Function
Function should only run once.
function once(fn) {
let called = false;
let result;
return function(...args) {
if (!called) {
result = fn(...args);
called = true;
}
return result;
};
}
const sayHello = once(() => "Hello");
console.log(sayHello()); // Hello
console.log(sayHello()); // Hello (still)
Problem 9: Caching / Memoization
Closures help cache results.
function memoize(fn) {
let cache = {};
return function(x) {
if (cache[x] !== undefined) {
return "From cache: " + cache[x];
}
let result = fn(x);
cache[x] = result;
return "Calculated: " + result;
};
}
const square = memoize(n => n * n);
console.log(square(4)); // Calculated: 16
console.log(square(4)); // From cache: 16
Problem 10: Module Pattern
Closures help simulate private methods.
const BankAccount = (function() {
let balance = 0;
return {
deposit: function(amount) {
balance += amount;
return balance;
},
withdraw: function(amount) {
if (amount <= balance) {
balance -= amount;
return balance;
}
return "Insufficient funds";
},
getBalance: function() {
return balance;
}
};
})();
console.log(BankAccount.deposit(100)); // 100
console.log(BankAccount.withdraw(30)); // 70
console.log(BankAccount.getBalance()); // 70