JavaScript
// Closure: Function has access to outer function's variables
// Example 1: Basic closure
function outerFunction(x) {
// Outer function's variable
let outerVar = x;
// Inner function (closure)
function innerFunction(y) {
console.log("Outer:", outerVar, "Inner:", y);
return outerVar + y;
}
return innerFunction;
}
let closure = outerFunction(10);
console.log("Result:", closure(5));
// Example 2: Counter using closure
function createCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
let counter1 = createCounter();
let counter2 = createCounter();
console.log("\nCounter 1:", counter1());
console.log("Counter 1:", counter1());
console.log("Counter 2:", counter2());
console.log("Counter 1:", counter1());
// Example 3: Private variables
function createBankAccount(initialBalance) {
let balance = initialBalance; // Private variable
return {
deposit: function(amount) {
balance += amount;
return balance;
},
withdraw: function(amount) {
if (amount <= balance) {
balance -= amount;
return balance;
} else {
return "Insufficient funds";
}
},
getBalance: function() {
return balance;
}
};
}
let account = createBankAccount(100);
console.log("\nInitial balance:", account.getBalance());
console.log("After deposit 50:", account.deposit(50));
console.log("After withdraw 30:", account.withdraw(30));
console.log("Final balance:", account.getBalance());
// Example 4: Function factory
function createMultiplier(multiplier) {
return function(number) {
return number * multiplier;
};
}
let double = createMultiplier(2);
let triple = createMultiplier(3);
console.log("\nDouble 5:", double(5));
console.log("Triple 5:", triple(5));
// Example 5: Closure with loop (common mistake)
console.log("\nClosure in loop:");
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log("var i:", i); // Prints 3, 3, 3
}, 100);
}
// Solution: Use let
for (let j = 0; j < 3; j++) {
setTimeout(function() {
console.log("let j:", j); // Prints 0, 1, 2
}, 200);
}Output
Outer: 10 Inner: 5 Result: 15 Counter 1: 1 Counter 1: 2 Counter 2: 1 Counter 1: 3 Initial balance: 100 After deposit 50: 150 After withdraw 30: 120 Final balance: 120 Double 5: 10 Triple 5: 15 Closure in loop: var i: 3 var i: 3 var i: 3 let j: 0 let j: 1 let j: 2
This program demonstrates closures in JavaScript.
Closure Definition
A closure is a function that has access to variables in its outer (enclosing) scope, even after the outer function has returned.
Example 1: Basic Closure
Inner function accesses outer variable:
javascriptfunction outer(x) { let outerVar = x; return function inner(y) { return outerVar + y; // Accesses outerVar }; }
How it works:
- Inner function "remembers" outer scope
- Variables persist after outer function returns
Example 2: Counter
Each closure has its own state:
javascriptfunction createCounter() { let count = 0; return function() { return ++count; }; }
Key Point: Each call to createCounter() creates a new closure with its own count variable.
Example 3: Private Variables
Encapsulation pattern:
javascriptfunction createBankAccount(balance) { return { deposit: function(amount) { balance += amount; // Accesses private balance } }; }
Benefits:
- Data privacy
- Prevents external modification
- Encapsulation
Example 4: Function Factory
Create specialized functions:
javascriptfunction createMultiplier(multiplier) { return function(number) { return number * multiplier; }; }
Example 5: Loop Closure Issue
Common mistake with var:
javascriptfor (var i = 0; i < 3; i++) { setTimeout(function() { console.log(i); // All print 3! }, 100); }
Problem: var is function-scoped, all closures share same i.
Solution: Use let (block-scoped):
javascriptfor (let i = 0; i < 3; i++) { setTimeout(function() { console.log(i); // Prints 0, 1, 2 }, 100); }
When to Use:
- Data privacy/encapsulation
- Function factories
- Event handlers
- Callbacks with state
- Module pattern
Memory Considerations:
- Closures keep variables in memory
- Can cause memory leaks if not careful
- Be mindful of large objects in closures