My translation station: Www.zcfy.cc/article/javascript-loops-and-scope
Translated text link: flaviocopes.com/javascript-loops-and-scope/
JavaScript has a feature that may cause headaches for developers, and is related to loops and scopes.
As an example:
const operations = []
for (var i = 0; i < 5; i++) {
operations.push(() => {
console.log(i)
})
}
for (const operation of operations) {
operation()
}
It basically loops 5 times and adds a function to the operations array. This function prints out the index value of the loop variablei.
After you run these functions
The expected result should be:
01234
But what actually happens is this:
55555
Why is this happening? Because it's usingvar.
Because thevarvariable is promoted, the above code is equivalent to the
var i;
const operations = []
for (i = 0; i < 5; i++) {
operations.push(() => {
console.log(i)
})
}
for (const operation of operations) {
operation()
}
Therefore, in the for-of loop,iIt is still visible, it is equal to 5, and each time it is involved in the functioni, this value will be used.
So what should we do to make it what we think it is?
The simplest scenario is to use aletdeclaration. Introduced in ES2015, they are a great help to avoidvarsome strange questions about the use of claims.
Simple in the loop variable willvarbecomelet, can run well:
const operations = []
for (let i = 0; i < 5; i++) {
operations.push(() => {
console.log(i)
})
}
for (const operation of operations) {
operation()
}
Here is the output:
01234
How does this work? This is because each time the loop repeats, it is recreatedi, and each function addsoperationsan array, which gets its owni.
Remember that you cannot useconstin this case, because this will causeforthe new value to be tried when the second loop is given an error.
Another very common solution to this problem is to use the PRE-ES6 code, which is called an instant call function expression (iife).
In this case, you can wrap the entire function andibind it on top of it. From this way, you are creating a function that can execute immediately, and you return from it with a new function. So we can execute it later.
const operations = []
for (var i = 0; i < 5; i++) {
operations.push(((j) => {
return () => console.log(j)
})(i))
}
for (const operation of operations) {
operation()
}