Understanding closures
Closures enable you to create functions that “remember” their surrounding context, allowing for dynamic and flexible behavior. A closure is formed when an inner function has access to the variables and parameters of an outer function, even after the outer function has finished executing. This unique behavior allows functions to “close over” their surrounding scope.
Basic Closure
function outer() {
const outerVariable = "I'm from outer!";
function inner() {
console.log(outerVariable);
}
return inner;
}
const closureFunc = outer();
closureFunc(); // Outputs "I'm from outer!"
Preserving State
Closures are often used to preserve the state of a variable across multiple function calls.
function counter() {
let count = 0;
return function () {
return ++count;
};
}
const increment = counter();
console.log(increment()); // 1
console.log(increment()); // 2
Callbacks and Asynchronous Operations
Closures are integral in handling asynchronous operations, such as callbacks.
function fetchData(url, callback) {
const data = fetch(url);
setTimeout(() => {
callback(data);
}, 1000);
}
fetchData("https://example.com", (data) => {
console.log(data);
});
Practical Uses
Data Privacy
Closures provide a way to encapsulate data and create private variables(we have newer #
syntax for private variables).
function createCounter() {
let count = 0;
return {
increment: () => ++count,
get: () => count,
};
}
const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.get()); // 2
Modular Design
Closures aid in achieving modular design and reducing global variable usage.
const app = (function () {
let counter = 0;
function increment() {
return ++counter;
}
return {
increment,
};
})();
console.log(app.increment()); // 1
console.log(app.increment()); // 2
What now?
Try to create as many different scenarios using closures.