A Closure is widely considered the single most celebrated yet misunderstood superpower of JavaScript. In formal computer science terms: a closure is a function that retains access to variables from its parent lexical environment, even after the parent function has completed execution and closed.
Figure 12: Visualizing Closures: The inner function retains a persistent reference to outer variables in Heap memory.
When an outer function returns an inner function, the inner function does NOT just return bare code. It carries an attached hidden closure scope containing all closed-over outer variables:
function createCounter() {
let count = 0; // Outer lexical variable
return function increment() {
count++; // Accesses 'count' via closure!
return count;
};
}
// Invoke createCounter: It returns the 'increment' function
const counter1 = createCounter();
// createCounter() has FINISHED executing and popped off Call Stack!
// Yet counter1 STILL remembers 'count':
console.log(counter1()); // 1
console.log(counter1()); // 2
console.log(counter1()); // 3
// A separate instance creates a completely independent closure:
const counter2 = createCounter();
console.log(counter2()); // 1 (Independent memory!)
Prior to native private class fields, closures were the only mechanism in JavaScript to enforce true private variables that cannot be tampered with from outside:
function createBankAccount(initialDeposit) {
let balance = initialDeposit; // PRIVATE variable (Cannot be accessed directly!)
return {
deposit(amount) {
if (amount > 0) balance += amount;
return `Deposited: ₹${amount}. New Balance: ₹${balance}`;
},
withdraw(amount) {
if (amount > balance) return "Insufficient funds!";
balance -= amount;
return `Withdrew: ₹${amount}. Balance: ₹${balance}`;
},
getBalance() {
return `Current Balance: ₹${balance}`;
}
};
}
const account = createBankAccount(5000);
console.log(account.getBalance()); // "Current Balance: ₹5000"
account.deposit(2000);
console.log(account.getBalance()); // "Current Balance: ₹7000"
// Attempting direct access:
console.log(account.balance); // undefined! (100% Secure & Private)
Exam Question: "Can closures cause memory leaks in JavaScript? Explain."
Answer: Yes. Because closed-over variables are stored in the Memory Heap and referenced by inner functions, the Garbage Collector cannot reclaim that memory as long as the inner function reference remains reachable in the application. Unused closures or lingering event listeners can lead to excessive memory consumption.
What does the 'this' keyword point to, and how do call, apply, and bind manipulate it? Proceed to: JavaScript 'this' Keyword & Call/Apply/Bind →
Accelerate your JavaScript mastery by studying these tightly connected core tutorials:
Creation phase vs Execution phase.
Lexical this vs dynamic function invocation.
Currying, partial applications, and factory functions.
Simulating private variables before private fields.