JavaScript Closures Cheatsheet
Debojyoti Saha
Posted on May 24, 2024
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.
đź’– đź’Ş đź™… đźš©
Debojyoti Saha
Posted on May 24, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.