Javascript closure
Created By: chatGPT
JavaScript closures are a fundamental concept that allows a function to maintain access to its lexical scope, even when the function is executed outside that scope. This means that inner functions can access variables of their outer function even after the outer function has completed its execution.
function outerFunction() {
let outerVariable = 'I am from outer function';
function innerFunction() {
console.log(outerVariable);
}
return innerFunction;
}
const myInnerFunction = outerFunction();
myInnerFunction(); // Logs: I am from outer function
In the example above,
outerFunction
defines a variable called outerVariable
and an inner function innerFunction
. When outerFunction
is called, it returns innerFunction
. Even though outerFunction
has finished executing, innerFunction
retains access to outerVariable
due to the closure created.function makeCounter() {
let count = 0;
return {
increment: function() {
count++;
return count;
},
decrement: function() {
count--;
return count;
},
getCount: function() {
return count;
}
};
}
const counter = makeCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.decrement()); // 1
console.log(counter.getCount()); // 1
In this
makeCounter
example, we encapsulate the count variable within the closure. The returned object has methods to increment, decrement, and retrieve the value of count. This way, the count variable is not directly accessible from outside, ensuring that it's manipulated only through the provided functions.function createMultiplier(multiplier) {
return function(number) {
return number * multiplier;
};
}
const double = createMultiplier(2);
const triple = createMultiplier(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15
The
createMultiplier
function demonstrates how closures can capture particular values. Each call to createMultiplier
generates a new function that multiplies its input by the multiplier
provided at the time of creation. Thus, the returned functions have unique environments storing the specific multiplier.const makeCounter = () => {
let count = 0;
return {
increment: () => ++count,
decrement: () => --count,
getCount: () => count
};
};
const counter = makeCounter();
console.log(counter.increment()); // 1
console.log(counter.getCount()); // 1
Here we see the use of arrow functions in the
makeCounter
example. Arrow functions also create closures, providing a more concise syntax while maintaining access to the surrounding context. They are particularly handy for methods in objects that belong to a closure.function countdown(num) {
return function() {
if (num > 0) {
console.log(num);
num--;
return countdown(num);
} else {
console.log('Countdown Finished!');
}
};
}
const startCountdown = countdown(5);
startCountdown();
startCountdown();
startCountdown();
startCountdown();
startCountdown();
startCountdown(); // Countdown Finished!
The
countdown
function shows how closures can keep state over multiple calls. Each time you invoke startCountdown
, it retains the value of num
within the closure, allowing the countdown process to continue until it reaches zero. This illustrates the power of closures in maintaining state in JavaScript.const adder = (x) => (y) => x + y;
const add5 = adder(5);
console.log(add5(3)); // 8
console.log(add5(10)); // 15
console.log(adder(10)(5)); // 15