If you’ve been writing JavaScript for a while, you've definitely used closures—whether you realized it or not. But if someone asks:
💬 “Hey, can you explain closures in simple terms?”
Many developers hesitate. So let’s break it down, once and for all! 🚀
** What is a Closure?**
A closure is when a function "remembers" the variables from its parent scope, even after the parent has finished executing.
💡 Think of it as a backpack 🎒 that a function carries around, filled with variables from where it was created.
Example – The Classic Trap ⚠️
Guess what happens here?
function createCounter() {
let count = 0;
return function () {
count++;
console.log(count);
};
}
const counter = createCounter();
counter(); // 1 ✅
counter(); // 2 ✅
counter(); // 3 ✅
💡 Why does this work?
Even though createCounter()
has finished executing, the inner function remembers count
because of closure.
It’s as if the function "locks in" the variables it had access to at creation time.
🤔 Where Do Closures Matter in Real Life?
✅ Data Privacy (Encapsulation)
function bankAccount(initialBalance) {
let balance = initialBalance;
return {
deposit(amount) {
balance += amount;
console.log(`New Balance: ${balance}`);
},
withdraw(amount) {
if (amount > balance) {
console.log("Insufficient funds!");
} else {
balance -= amount;
console.log(`New Balance: ${balance}`);
}
}
};
}
const myAccount = bankAccount(1000);
myAccount.deposit(500); // New Balance: 1500
myAccount.withdraw(300); // New Balance: 1200
console.log(myAccount.balance); // ❌ Undefined (private variable)
Here, balance
isn’t directly accessible from the outside—it’s truly private! 💡
✅ Event Listeners & Async Code
function delayedMessage(msg, delay) {
setTimeout(() => {
console.log(msg);
}, delay);
}
delayedMessage("Hello after 3 seconds!", 3000);
Even though delayedMessage
finishes running, the callback inside setTimeout
still has access to msg
because of closure!
🚨 Common Pitfall – Closures and Loops
for (var i = 1; i <= 3; i++) {
setTimeout(() => console.log(i), 1000);
}
💡 You expect: 1, 2, 3
❌ But you get: 4, 4, 4
Why? The callback inside setTimeout
gets the final value of i
(which is 4) when it executes.
✅ Fix: Use let
(block scope) or an IIFE
for (let i = 1; i <= 3; i++) {
setTimeout(() => console.log(i), 1000);
}
Now, each iteration remembers its own i
thanks to closure! 🎯
** Final Takeaways**
1️⃣ Closures "remember" variables from their parent scope, even after execution finishes.
2️⃣ They help with data privacy, async behavior, and event handling.
3️⃣ Watch out for closures inside loops—use let
or IIFE to avoid unexpected results.
Closures are everywhere in JavaScript. Master them, and you'll unlock better debugging skills, performance optimizations, and cleaner code.
📢 Let's Connect!
🚀 Follow me on LinkedIn for more deep dives into JavaScript and backend engineering.
🔗 Check out my GitHub for open-source projects and code samples.
📩 Have questions or want to collaborate? Reach me at imhamzaa313@gmail.com.