Closures are one of the most powerful and important concepts in JavaScript. They are widely used in:
React Applications
Event Handlers
Timers
Callbacks
Data Privacy
Function Factories
JavaScript Frameworks
Many developers can write JavaScript code without understanding closures, but mastering closures helps you become a better programmer and perform well in technical interviews.
In this article, we will learn:
What a closure is
Lexical scope
Scope chain
How closures work
Why closures are useful
Private variables
Function factories
Real-world examples
Interview questions
What is a Closure?
A closure is created when:
A Function
Remembers
Variables From Its Outer Scope
Even After The Outer Function Has Finished Executing
This definition may sound confusing initially, so let's understand it step by step.
Understanding Scope
Before learning closures, we must understand scope.
Scope determines where variables can be accessed.
Example:
let name = "Rahul";
function show()
{
console.log(name);
}
show();
Output:
Rahul
The function can access variables from its outer scope.
Lexical Scope
JavaScript uses Lexical Scope.
This means:
Functions Can Access Variables
Defined In Their Parent Scope
Example:
function outer()
{
let message = "Hello";
function inner()
{
console.log(message);
}
inner();
}
outer();
Output:
Hello
Why Does This Work?
Because:
inner()
is inside
outer()
Therefore:
inner()
can access
message
What Happens After outer() Finishes?
Normally:
Local Variables
Should Be Destroyed
But closures create an exception.
First Closure Example
function outer()
{
let count = 0;
function inner()
{
count++;
console.log(count);
}
return inner;
}
let counter = outer();
counter();
counter();
counter();
Output:
1
2
3
Why is This Surprising?
After:
let counter =
outer();
The outer function finishes execution.
Normally:
count
should disappear
But it doesn't.
The inner function remembers it.
This remembered connection is called:
Closure
Closure Visualization
outer()
│
├── count = 0
│
└── inner()
│
▼
remembers count
Even after outer() finishes:
count
still exists
because inner() uses it.
Step-by-Step Dry Run
Initial:
counter = outer();
Creates:
count = 0
Returns:
inner()
First call:
counter();
Execution:
count = 1
Output:
1
Second call:
counter();
Execution:
count = 2
Output:
2
Third call:
counter();
Execution:
count = 3
Output:
3
Why Closures Are Useful
Closures allow:
Data persistence
Data privacy
State management
Function customization
Real-Life Example
Imagine a bank account.
You should not directly access balance.
Instead:
Deposit
Withdraw
Check Balance
should be controlled.
Closures help achieve this.
Private Variable Example
function bankAccount()
{
let balance = 1000;
return {
deposit(amount)
{
balance += amount;
},
showBalance()
{
console.log(balance);
}
};
}
let account =
bankAccount();
account.deposit(500);
account.showBalance();
Output:
1500
Why is balance Private?
Because:
balance
exists only inside:
bankAccount()
Outside code cannot access it directly.
Example:
console.log(
account.balance
);
Output:
undefined
Function Factory
Closures can create customized functions.
Example:
function multiplyBy(x)
{
return function(y)
{
return x * y;
};
}
Creating Functions
let double =
multiplyBy(2);
let triple =
multiplyBy(3);
Usage
console.log(
double(5)
);
Output:
10
console.log(
triple(5)
);
Output:
15
How It Works
For:
double(5)
JavaScript remembers:
x = 2
through closure.
Closure with setTimeout
Example:
function greet()
{
let name = "Rahul";
setTimeout(
function()
{
console.log(name);
},
2000
);
}
greet();
Output after 2 seconds:
Rahul
Why Does It Work?
Even though:
greet()
finished executing,
the callback remembers:
name
through closure.
Practical Example – Click Counter
function createCounter()
{
let count = 0;
return function()
{
count++;
console.log(count);
};
}
let counter =
createCounter();
counter();
counter();
counter();
Output:
1
2
3
Multiple Independent Closures
let counter1 =
createCounter();
let counter2 =
createCounter();
Usage:
counter1();
counter1();
counter2();
Output:
1
2
1
Each closure maintains its own state.
Closure and Memory
Closures keep variables alive.
Example:
function test()
{
let data =
"Important Data";
return function()
{
console.log(data);
};
}
The variable remains in memory while the returned function exists.
Advantages of Closures
Data privacy
State preservation
Cleaner code
Reusable functions
Encapsulation
Common Interview Question
Question
What is a Closure?
Answer
A closure is a function that remembers and can access variables from its lexical scope even after the outer function has completed execution.
Interview Example
function outer()
{
let x = 10;
return function()
{
console.log(x);
};
}
let fn =
outer();
fn();
Output:
10
Reason:
Closure remembers x
Common Mistakes Beginners Make
Confusing Scope with Closure
Scope:
Where variable exists
Closure:
Remembering variable
after scope ends
Creating Unnecessary Closures
Too many closures can increase memory usage.
Use them only when needed.
Forgetting That Closures Store References
Example:
let value = 10;
function show()
{
console.log(value);
}
value = 20;
show();
Output:
20
Closures remember the variable, not a copy of its value.
Real-World Applications
Closures are used in:
React Hooks
Event Handlers
Timers
API Callbacks
Authentication Systems
Private Variables
State Management Libraries
Modern JavaScript frameworks rely heavily on closures.
Complete Program
function createCounter()
{
let count = 0;
return function()
{
count++;
console.log(
count
);
};
}
let counter =
createCounter();
counter();
counter();
counter();
Output:
1
2
3
Closure vs Normal Function
| Feature | Normal Function | Closure |
|---|---|---|
| Remembers Variables | No | Yes |
| Preserves State | No | Yes |
| Data Privacy | No | Yes |
| Useful for Encapsulation | No | Yes |
Conclusion
Closures are one of the most powerful features of JavaScript. They allow functions to remember variables from their outer scope, preserve state, and create private data.
Comments
Post a Comment