hllizi

friendly old nag

php programmer by day, no php programmer by night


parappayo
@parappayo

I keep forgetting about this but it should be obvious to JS experts who work in it a lot. JS lambdas don't capture the value of variables at the time they're defined, but rather use reference semantics. This combines with the fact that the var keyword doesn't follow C style scoping rules to sometimes frustrate people.

The following does what you'd expect:

let funcs = [];

for (let i = 0; i < 5; i++) {
	funcs.push(() => console.log(i));
}

funcs.forEach(x => x());

It outputs the numbers 0 through 4.

This slight variation does something different:

let funcs = [];

for (var i = 0; i < 5; i++) {
	funcs.push(() => console.log(i));
}

funcs.forEach(x => x());

As noted in the MDN docs, var i does not create a new scope (whereas let i does), so each of the lambdas captures the same reference to i. It outputs the number 5 five times.

Just because you're using let doesn't mean you won't get burned:

let funcs = [];
let x = 0;

for (let i = 0; i < 5; i++) {
	x = i;
	funcs.push(() => console.log(x));
}

funcs.forEach(x => x());

For the same reason that var i didn't give us what we probably expected, having x outside of the scope of the loop also causes each of the lambdas to have the same reference. This version outputs the number 4 five times.


You must log in to comment.