A closure in JavaScript is created when a function remembers and accesses variables from its outer (lexical) scope, even after that outer function has finished executing.
Closures are one of the most powerful and important concepts in JavaScript, enabling data privacy, function factories, and advanced functional programming patterns.
What is a Closure?
A closure is the combination of a function and the lexical environment in which it was declared.
It allows inner functions to access variables defined in their outer function scope even after the outer function has returned.
Basic Example of Closure
In this example, the inner function remembers the variable from its outer function.
function outer() {
let count = 0;
function inner() {
count++;
console.log(count);
}
return inner;
}
const counter = outer();
counter();
counter();Even though outer() has finished execution, the inner function still has access to the variable count.
How Closures Work Internally
Closures work because JavaScript uses lexical scoping, meaning functions are executed using the scope in which they were defined.
When a function is returned, it retains a reference to its outer scope variables.
Lexical Scope and Closures
Lexical scope means a function can access variables from its parent scope at the time of definition.
Closures extend this concept by preserving access even after the parent function execution is complete.
function greet() {
let name = 'John';
return function () {
console.log('Hello ' + name);
};
}
const sayHello = greet();
sayHello();Practical Use: Data Encapsulation
Closures are often used to create private variables that cannot be accessed directly from outside the function.
This helps in achieving data encapsulation in JavaScript.
function createBankAccount() {
let balance = 0;
return {
deposit(amount) {
balance += amount;
},
getBalance() {
return balance;
}
};
}
const account = createBankAccount();
account.deposit(100);
console.log(account.getBalance());Function Factories
Closures allow us to create function factories that generate specialized functions dynamically.
Each generated function retains its own independent lexical environment.
function multiply(x) {
return function (y) {
return x * y;
};
}
const double = multiply(2);
console.log(double(5));Common Mistakes with Closures
A common mistake is assuming the value is copied instead of referenced inside a closure.
This often causes unexpected results in loops using var instead of let.
for (var i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i);
}, 100);
}This prints 3 three times because var is function-scoped, not block-scoped.
Fixing Closure Issues with let
Using let instead of var creates a new block scope for each iteration.
for (let i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i);
}, 100);
}Real-World Usage
Closures are widely used in event handlers, React hooks, memoization, and module patterns.
They are essential in modern JavaScript frameworks and libraries.
Best Practices
Use closures intentionally for encapsulation rather than accidentally creating memory leaks.
Be mindful of retained references in long-running applications.
Summary
Closures allow functions to retain access to their lexical scope even after execution.
Mastering closures is essential for advanced JavaScript development and understanding frameworks like React.