JavaScript is packed with powerful features, and one of the most fundamental yet often confusing concepts is closures. If you’ve ever encountered a function inside another function and wondered how it retains access to its parentβs variables, you’re dealing with a closure.
In this blog, we’ll break down closures with a real-world analogy, explain their technical workings, and provide practical code examples to solidify your understanding.
π What is a Closure?
A closure is a function that remembers the variables from its outer scope even after the outer function has finished executing.
π₯ Real-World Analogy
Imagine you work at a coffee shop, and your manager gives you a special discount code to use for the rest of the week. Even if your manager leaves the store, you still remember the code and can apply the discount for customers.
Similarly, in JavaScript, an inner function remembers the variables of its parent function, even if the parent function has executed and returned.
Example of Closures
function outerFunction() {
let message = "Hello, I remember you!"; // Variable inside outer function
function innerFunction() {
console.log(message); // Inner function accessing outer variable
}
return innerFunction;
}
const myClosure = outerFunction(); // outerFunction runs and returns innerFunction
myClosure(); // Logs: "Hello, I remember you!"
Explanation:
outerFunction
declares a variablemessage
and definesinnerFunction
inside it.innerFunction
accessesmessage
from its parent scope.- When
outerFunction
is called, it returnsinnerFunction
. - Even though
outerFunction
has finished executing, the returnedinnerFunction
remembersmessage
because of the closure.
π‘ Practical Use Cases of Closures
Closures arenβt just theoreticalβthey power many JavaScript patterns! Letβs explore real-world applications of closures.
Data Privacy (Encapsulation)
Closures allow us to create private variables that cannot be accessed directly from outside.
function bankAccount(initialBalance) {
let balance = initialBalance; // Private variable
return {
deposit: function (amount) {
balance += amount;
console.log(`Deposited: $${amount}. New Balance: $${balance}`);
},
getBalance: function () {
console.log(`Balance: $${balance}`);
}
};
}
const myAccount = bankAccount(1000);
myAccount.deposit(500); // Deposited: $500. New Balance: $1500
myAccount.getBalance(); // Balance: $1500
// myAccount.balance; β ERROR: Cannot access balance directly
Function Factories
Closures enable function factories, where a function creates and returns new functions with preset behavior.
function discount(discountRate) {
return function (price) {
return price - price * discountRate;
};
}
const studentDiscount = discount(0.1); // 10% discount
const blackFridayDiscount = discount(0.5); // 50% discount
console.log(studentDiscount(100)); // 90
console.log(blackFridayDiscount(100)); // 50
Event Handlers and Callbacks
Closures are commonly used in event listeners and asynchronous operations.
function buttonClickHandler(message) {
return function () {
console.log(message);
};
}
document.getElementById("myButton").addEventListener("click", buttonClickHandler("Button clicked!"));
Summary
- A closure allows a function to retain access to variables from its outer function even after the outer function has executed.
- It is like a coffee shop employee remembering a discount code after the manager leaves.
- Practical uses of closures include:
- Data privacy (hiding variables)
- Function factories (preset behavior)
- Event handlers and callbacks (retaining state)
Closures are a must-know concept in JavaScript and are used extensively in frameworks like React, Node.js, and beyond.
Now go ahead and experiment with closures!Β π