Ever wondered how a bank keeps your balance private — so no one else can just walk in and change it?
That's exactly what a closure does in JavaScript. It locks your data away and only lets you touch it through specific actions — like a deposit or withdrawal.
Let's break it down with a real banking example. 🏦
1. What Is a Closure?
Imagine you open a bank account. The bank creates a private locker for you — your balance, your account number. No one else can access it directly. You can only interact with it through the bank's services: deposit, withdraw, check balance.
In JavaScript, a closure is when an inner function "remembers" the variables from the outer function — even after the outer function has finished running.
That's it. That's the whole idea. 🎉
2. What Does the Code Look Like?
Here's the full createAccount function we'll be working with:
function createAccount(userName, initialBalance) {
let balance = initialBalance; // private
let accountNumber = Math.floor(Math.random() * 100000);
function deposit(amount) {
balance += amount;
return `${userName} deposited ₹${amount}. Balance: ₹${balance}`;
}
function withdraw(amount) {
if (amount > balance) {
return "Insufficient balance";
}
balance -= amount;
return `${userName} withdrew ₹${amount}. Balance: ₹${balance}`;
}
function getBalance() {
return `${userName}'s balance is ₹${balance}`;
}
return {
accountNumber,
deposit,
withdraw,
getBalance
};
}
createAccount is the outer function. It holds balance and userName as private variables inside it.
deposit, withdraw, and getBalance are the inner functions. Each one is a closure — they can all see and use balance even after createAccount has finished running.
3. Why Can Inner Functions Still Access balance?
When createAccount runs and returns, you'd think balance is gone forever, right?
Nope. 🙅
JavaScript keeps balance alive in memory because the inner functions still hold a reference to it. This "remembered environment" is called the closure.
Think of it like this — even after the bank teller goes home, your locker is still safely locked inside the vault. The locker doesn't disappear. It stays as long as you still hold the keys.
4. How Does Each User Get Their Own Private Balance?
const user1 = createAccount("Ravi", 1000);
const user2 = createAccount("Anu", 5000);
const user3 = createAccount("Karthik", 200);
Every call to createAccount creates a brand new closure — a completely separate private environment.
-
user1gets its ownbalancestarting at ₹1000 -
user2gets its ownbalancestarting at ₹5000 -
user3gets its ownbalancestarting at ₹200
Ravi's deposit will never affect Anu's balance. Each account is fully isolated. 🔒
5. How Do You Use the Returned Methods?
console.log(user1.getBalance());
// Ravi's balance is ₹1000
console.log(user1.deposit(500));
// Ravi deposited ₹500. Balance: ₹1500
console.log(user2.withdraw(1000));
// Anu withdrew ₹1000. Balance: ₹4000
Every time you call user1.deposit(500), the closure remembers Ravi's balance and updates it. The next time you call user1.getBalance(), it shows the updated value.
The closure is keeping score behind the scenes — silently, reliably. 📝
6. There's a Bug in the Code — Did You Catch It?
Look at this line from the original code:
console.log(user2.getBalance) // ❌ Missing ()
console.log(user1.getBalance()) // ✅ Correct
user2.getBalance without () does not call the function. It just prints the function itself:
[Function: getBalance]
Always add () when you actually want to call the function and get a result. Easy mistake — now you'll never forget! 😄
7. Why Is balance Considered "Private"?
Try accessing balance directly from outside:
console.log(user1.balance); // undefined
It returns undefined because balance is not part of the returned object. It lives only inside the closure.
The only way to read or change it is through deposit(), withdraw(), or getBalance(). That's data privacy powered by closures — no one can sneak in and tamper with it directly.
8. The Mental Model — Picture It Like This
createAccount("Ravi", 1000)
│
├── 🔒 Private Vault (closure)
│ ├── balance = 1000
│ └── userName = "Ravi"
│
└── 🗝️ Keys Returned to You
├── deposit() → updates balance
├── withdraw() → updates balance
└── getBalance() → reads balance
The vault is the closure. The keys are the inner functions. You can only touch what's inside through the keys.
Quick Summary — 3 Golden Rules of Closures
Inner functions remember outer variables — even after the outer function has finished running, the inner functions still hold on to those variables.
Each function call creates its own closure —
user1,user2, anduser3each have their own privatebalancethat never leaks into each other.Closures give you data privacy — if
balanceisn't in the returned object, no one outside can access or modify it directly.
Closures sound scary at first — but once you picture them as a private vault with keys, they just click. 🔑
Drop a comment if you have questions. And if this made closures finally make sense, smash that ❤️ and share it with a friend who's learning JavaScript. 🚀
Top comments (0)