Closures are often regarded as one of the most complex concepts in JavaScript, but once understood, they unlock immense power. Every time a function is created in JavaScript, a closure is formed.
What is a Closure?
A closure is the lexical environment within which a function was declared. It preserves variable references from outer scopes even when the outer function completes execution.
Lexical Scoping
JavaScript uses lexical scoping, which means the scope of a variable is determined by its physical location in the source code. Nested inner functions have access to variables declared in their outer scopes.
function init() {
var name = 'Mozilla'; // name is a local variable created by init
function displayName() {
console.log(name); // displayName() uses variable declared in parent function
}
displayName();
}
init();
Practical Use Cases
1. Data Encapsulation & Private Variables
Since JavaScript didn't historically support private properties in classes, closures were the standard way to hide state from the outside world:
function createBankAccount(initialBalance) {
let balance = initialBalance; // Private variable
return {
deposit(amount) { balance += amount; },
withdraw(amount) {
if (amount <= balance) {
balance -= amount;
return amount;
}
return 'Insufficient funds';
},
getBalance() { return balance; }
};
}
const account = createBankAccount(100);
account.deposit(50);
console.log(account.getBalance()); // 150
console.log(account.balance); // undefined (cannot access directly!)
2. Function Factories
Creating functions that are customized based on the arguments passed to the outer factory function:
function makeMultiplier(factor) {
return function(number) {
return number * factor;
};
}
const double = makeMultiplier(2);
const triple = makeMultiplier(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15