Overview
JS closures are functions that can access values outside of their own curly braces
- When a function is created, it has access to a reference to all the variables declared around it, also known as lexical environment. The combo of the function and its environment is called a closure.
function createAdder(a) {
function adder(b) {
return a + b;
}
return adder;
}
const f = createAdder(3);
console.log(f(5)); // 3 + 5 = 8createAdderpasses the 1st parameteraand the inner function has access to itcreateAdderserves as a factory of new functions, which each returned function having different behavior
A closure is created when a function is defined inside another function, and theĀ inner function references variables in the outer functionās scope. When the inner function is returned from the outer function, it retains a reference to the outer functionās scope, and can continue to access those variables even after the outer function has finished executing. Vice-Versa is not true!!
function outer() {
let x = 10; // x is created
return function inner() {
console.log(x); // inner "remembers" x
};
}
const myFunc = outer(); // outer() runs, x = 10, and returns inner
myFunc(); // prints 10 because inner() still remembers x- Here,
innerforms a closure overx, keeping access to it even thoughouter()has already executed.
Example 1
/**
* @param {number} n
* @return {Function} counter
*/
var createCounter = function(n) {
return function() {
return n++;
};
};
/**
* const counter = createCounter(10)
* counter() // 10
* counter() // 11
* counter() // 12
*/- it returns a value and then increments it
- so this is true encapsulation because in theory you canāt have access to n
Example 2- trick question!
using var
for (var i = 0; i < 3; i++) {
const log = () => { // <-- Closure starts here
console.log(i); // <-- `log` captures `i`
}; // <-- Closure ends here
setTimeout(log, 100); // 3,3,3
}
logcaptures the variablei, which is declared usingvar(function-scoped).varis hoisted up, meaning itās declared once for the entire function.- All iterations of the loop reuse the same
i - Each time we define
logit captures the samei(which keeps changing) - By the time
setTimeoutexecutes, the loop has already finished, andiis 3, so every log function prints 3 ā Closures capture references to variables, not their values at the time of capture.- So this is why it always gets the latest value!
using let
for (let i = 0; i < 3; i++) {
const log = () => { // <-- Closure starts here
console.log(i); // <-- `log` captures `i`
}; // <-- Closure ends here
setTimeout(log, 100);
}let iis block-scoped, meaning a newiis created for each loop iteration.- Each iteration creates a new, independent
i, which only exists in that specific iteration. - The function
logforms a closure over that specifici, so it remembers the value from that iteration. - Even though
setTimeoutruns later,logstill remembers the correctifor each iteration.