In JavaScript, we don't have block scope, only function scope.
In the first example, the only i
declared belongs to the createAdders
scope, meaning all functions created in the for
loop will seek up in the scope chain the same i
and return the same value. Explained with code:
// here's the only `i` declaration
for (var i = 1; i < 4; i++) {
fns[i] = (function (n) {
return i + n; //this line will retrieve the `i` variable declared above,
//that being always 4 after the loop ends
});
}
In the second example, you're creating a new scope with an IIFE inside the loop - it creates a new execution context for each iteration.
A function created inside of the IIFE will access the IIFE's execution context's i
. This i
is unique for each iteration as you're passing the outer i
to the IIFE, which becomes the IIFE's formal parameter i
.
In short, each iteration creates a new execution context with its own i
through an IIFE wrapper.
Read the comments in order:
// 1. Outer `i` declared here
for (var i = 1; i < 4; i++) {
(function (i) {// 3. Outer `i` becomes the formal parameter `i` of the IIFE,
// it is a "different" `i` in a new execution context (scope)
fns[i] = (function (n) {
return i + n; // 4. seeks the `i` value of the IIFE
});
})(i) // 2. Outer `i` passed to IIFE
}
When you invoke the function(s) created inside of the IIFE, the scope chain will retrieve the "closest" i
in the scope chain, that being the formal parameter i
of the IIFE in which the function was created.