⚡
Closures and Lexical Scope
Advanced
130 XP
55 min
Lesson Content
Closures and Lexical Scope
A closure is a function that has access to variables in its outer (enclosing) lexical scope, even after the outer function has returned. Closures are fundamental to JavaScript and enable powerful patterns.
What is a Closure?
function outer() {
let outerVar = 'I am outside!';
function inner() {
console.log(outerVar); // Can access outerVar
}
return inner;
}
const innerFunc = outer();
innerFunc(); // 'I am outside!' - closure preserved outerVarCommon Closure Patterns
// Module pattern
const counter = (function() {
let count = 0;
return {
increment: () => ++count,
decrement: () => --count,
getCount: () => count
};
})();
// Function factories
function createMultiplier(multiplier) {
return function(number) {
return number * multiplier;
};
}
const double = createMultiplier(2);
const triple = createMultiplier(3);Closures in Loops
// Problem: All functions reference same variable
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // Prints 3, 3, 3
}
// Solution: Use let or IIFE
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // Prints 0, 1, 2
}Practical Uses
- Data privacy and encapsulation
- Function factories
- Event handlers
- Memoization
- Currying
Example Code
Create and use closures for data privacy and function factories
// Module pattern with closure
const bankAccount = (function() {
let balance = 0;
return {
deposit: function(amount) {
balance += amount;
return balance;
},
withdraw: function(amount) {
if (amount <= balance) {
balance -= amount;
return balance;
}
return 'Insufficient funds';
},
getBalance: function() {
return balance;
}
};
})();
console.log('Initial:', bankAccount.getBalance());
console.log('After deposit:', bankAccount.deposit(100));
console.log('After withdraw:', bankAccount.withdraw(30));
console.log('Balance:', bankAccount.getBalance());
// Function factory
function createGreeter(greeting) {
return function(name) {
return `${greeting}, ${name}!`;
};
}
const sayHello = createGreeter('Hello');
const sayHi = createGreeter('Hi');
console.log(sayHello('Alice'));
console.log(sayHi('Bob'));
// Memoization with closure
function memoize(fn) {
const cache = {};
return function(...args) {
const key = JSON.stringify(args);
if (cache[key]) {
return cache[key];
}
const result = fn(...args);
cache[key] = result;
return result;
};
}
const slowFunction = (n) => {
// Simulate slow operation
return n * 2;
};
const fastFunction = memoize(slowFunction);
console.log('First call:', fastFunction(5));
console.log('Cached call:', fastFunction(5));Expected Output:
Initial: 0 After deposit: 100 After withdraw: 70 Balance: 70 Hello, Alice! Hi, Bob! First call: 10 Cached call: 10
Study Tips
- •Read the theory content thoroughly before practicing
- •Review the example code to understand key concepts
- •Proceed to the Practice tab when you're ready to code