I am quite confused about the closing behaviour of functions declared inside of for loops, in particular about variables defined in initializers:
function createFunctions(){
const functions = []
for(let i = 0; i < 5; i++)
functions.push(() => i);
return functions;
}
const results = createFunctions().map(m => m())
// results: [0, 1, 2, 3, 4]
vs
function createFunctions(){
const functions = []
let i;
for(i = 0; i < 5; i++)
functions.push(() => i);
return functions;
}
const results = createFunctions().map(m => m())
// results: [5, 5, 5, 5, 5]
Since the anonymous arrow function declared in the for loop captures its scope, I would expect both cases to yield [5, 5, 5, 5, 5]
, since at call time, i's value is 5. The first result however seems to suggest that on each iteration through the loop, i is a different variable. However, if you repeat the test but the initialized variable is an object instead of a number:
function createFunctions(){
const functions = []
for(let obj = {}, i = 0; i < 5; i++)
functions.push(() => obj);
return functions;
}
const results = createFunctions().map(m => m())
// results: [{}, {}, {}, {}, {}]; results[0] === results[1]: true
we can see that all elements in the returned array are referentially equal, and so are not different variables. So it seems that the way that functions close over variables declared in the for loop initializer changes depending on whether the variable is a primitive or not, which sounds preposterous to me.
What am I missing?