Closures in JavaScript
A closure in JavaScript is one of the most powerful and important concepts in the language. A closure happens when a function “remembers” the variables from its outer scope, even after that outer function has finished executing.
Closures make it possible to preserve state, create private variables, and build modular, maintainable code.
How Closures Work
When a function is created inside another function, the inner function forms a scope chain that includes:
- Its own local variables,
- The variables of the outer function, and
- Global variables.
Even if the outer function finishes execution, the inner function still “remembers” the environment in which it was created.
That preserved environment is what we call a closure.
Basic Example of a Closure
function outerFunction() {
let count = 0; // variable in outer scope
function innerFunction() {
count++;
console.log(`Current count: ${count}`);
}
return innerFunction;
}
const counter = outerFunction();
counter(); // Output: Current count: 1
counter(); // Output: Current count: 2
counter(); // Output: Current count: 3
Real-World Example: Private Variables
Closures are often used to create private data — variables that can’t be accessed directly from outside a function.
function createBankAccount(initialBalance) {
let balance = initialBalance; // private variable
return {
deposit(amount) {
balance += amount;
console.log(`Deposited: ${amount}, New Balance: ${balance}`);
},
withdraw(amount) {
if (amount <= balance) {
balance -= amount;
console.log(`Withdrew: ${amount}, New Balance: ${balance}`);
} else {
console.log("Insufficient funds!");
}
},
getBalance() {
return balance;
}
};
}
const myAccount = createBankAccount(1000);
myAccount.deposit(500);
myAccount.withdraw(300);
console.log(myAccount.getBalance()); // Output: 1200
Closures Inside Loops
A common place where developers encounter closures is inside loops.
Example Problem:
for (var i = 1; i <= 3; i++) {
setTimeout(() => console.log(i), 1000);
}
Solution using Closure or let
:
for (let i = 1; i <= 3; i++) {
setTimeout(() => console.log(i), 1000);
}
OR using a closure:
for (var i = 1; i <= 3; i++) {
((num) => {
setTimeout(() => console.log(num), 1000);
})(i);
}
Practical Use Cases of Closures
Use Case | Description | Example |
---|---|---|
Data Privacy | Hide variables from global scope | Private counters, stateful components |
Event Handlers | Remember values when events trigger later | Button click handlers |
Functional Programming | Create functions with pre-configured data | makeAdder(5) returning a function that adds 5 |
State Management | Preserve state without global variables | Counters, score tracking, timers |
Example: Function Factory Using Closures
function makeAdder(x) {
return function(y) {
return x + y;
};
}
const add5 = makeAdder(5);
const add10 = makeAdder(10);
console.log(add5(2)); // Output: 7
console.log(add10(2)); // Output: 12