1. What is a Closure?
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment)
2. Basic Example
function outerFunction() {
let outerVariable = 'I am outside!';
function innerFunction() {
console.log(outerVariable);
}
return innerFunction;
}
const myFunction = outerFunction();
myFunction(); // Output: I am outside!
3. Lexical Scoping
Closures work by capturing variables from their lexical environment.
function makeCounter() {
let count = 0;
return function() {
count++;
return count;
}
}
const counter = makeCounter();
console.log(counter()); // 1
console.log(counter()); // 2
4. Immediately Invoked Function Expression (IIFE)
IIFEs create closures to encapsulate variables.
const increment = (function() {
let counter = 0;
return function() {
counter++;
return counter;
}
})();
console.log(increment()); // 1
console.log(increment()); // 2
5. Closure with Loop (Common Pitfall)
Using var
in a loop can lead to unexpected behavior due to function-level scope.
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
// Output: 3, 3, 3
Solution with let
:
for (let i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
// Output: 0, 1, 2
6. Data Privacy
Closures can be used to emulate private variables.
function createSecretHolder(secret) {
let secretValue = secret;
return {
getSecret: function() {
return secretValue;
},
setSecret: function(newSecret) {
secretValue = newSecret;
}
};
}
const holder = createSecretHolder('mySecret');
console.log(holder.getSecret()); // 'mySecret'
holder.setSecret('newSecret');
console.log(holder.getSecret()); // 'newSecret'
7. Partial Application
Closures can be used for partial function application.
function add(a) {
return function(b) {
return a + b;
}
}
const addFive = add(5);
console.log(addFive(3)); // 8
8. Function Factories
Closures enable function factories.
function multiplier(factor) {
return function(number) {
return number * factor;
}
}
const double = multiplier(2);
console.log(double(5)); // 10
const triple = multiplier(3);
console.log(triple(5)); // 15
9. Module Pattern
The module pattern uses closures to create public and private methods.
const Module = (function() {
let privateVar = 'I am private';
function privateMethod() {
console.log(privateVar);
}
return {
publicMethod: function() {
privateMethod();
}
};
})();
Module.publicMethod(); // 'I am private'
10. Handling Asynchronous Closures
function createCounter() {
let count = 0;
return {
increment: function() {
count++;
return count;
},
getCount: function() {
return count;
}
};
}
const asyncCounter = createCounter();
setTimeout(() => {
asyncCounter.increment();
console.log(asyncCounter.getCount()); // 1
}, 1000);
11. Closures in Event Listeners
function setupButton() {
let clickCount = 0;
document.getElementById('myButton').addEventListener('click', function() {
clickCount++;
console.log(`Button clicked ${clickCount} times`);
});
}
setupButton();
12. Common Use Cases
- Encapsulation: Protecting variables from being accessed or modified outside their intended context.
- Callbacks: Passing a function as an argument to be executed later.
- Event Handlers: Managing event-driven programming.
- Functional Programming: Creating higher-order functions and function factories.
13. Best Practices
- Minimize the use of closures for better memory management.
- Be mindful of scope and lifetime of variables.
- Use
const
orlet
instead ofvar
to avoid common pitfalls with closures in loops.
Top comments (2)
A closure is not a function. If your definition were correct then there would be no point having separate words for 'closure' and 'function' since ALL functions have this capability.
Misconceptions About Closures
Jon Randy ποΈ γ» Sep 27 '23
Some comments have been hidden by the post's author - find out more