Closures
— JavaScript, Functional Programming
Closure is a mechanism that allows an inner function to gain access to the variables from the outer/parent function scope, regardless of the context that the function was invoked.
The closure is created with every function creation. To create a closure you have to define a function or an object that contains functions as properties inside another function and return it. If the returning function in its definitions refers to any values from the parent scope, it will have access to these variables during the runtime.
The main reason to use closures is the fact that they allow us to encapsulate the state and keep it private and control them through public interfaces.
Closures are often used in a technique called Partial Application, but at this moment let's focus just on closures.
1function createCounter () {2 let value = 03 return {4 increment: () => { value += 1 },5 decrement: () => { value -= 1 },6 getValue: () => value7 }8}910const counter = createCounter()11counter.increment() 12counter.getValue() // 1
If you are preparing for the job interview it is a high probability that you will be asked about the closures. The typical question looks like: What will be the result of the below code snippet?
1let i;2for (i = 0; i < 3; i++) {3 const log = () => {4 console.log(i);5 }6 setTimeout(log, 100);7}
In the above example, the i variable is defined in the global scope. Each time the new log function is created, it's also created a new closure with the global i variable. Because the execution of each new log function is delayed of 100ms, any log function will be fired at least after the loop execution. It means that the value of i variable at the end equals 3. As a result, 3 will be printed three times.
1// 32// 33// 3
To fix this behavior and receive digits 0, 1, 2, we have to declare the i variable as a counter, instead of declaring this variable in the global scope. Now when the closure is created it refers to the current value of the loop counter instead of the global variable.
1for (let i = 0; i < 3; i++) {2 const log = () => {3 console.log(i);4 }5 setTimeout(log, 100);6}7// 18// 29// 3