3

The following piece of code prints out "K" 16 times.

var rest = "KLMNOPQRSTUVWXYZ".split(""), fns = {};
for (var i=0; i<rest.length; i++) {
    (function(i){
        fns[rest[i]] = function() {
            console.log(rest[i]);
        };
        fns.K();
    })(i);
}

This piece of code prints out all the alphabets "K", "L" ....... "Y", "Z"

var rest = "KLMNOPQRSTUVWXYZ".split(""), fns = {};
for (var i=0; i<rest.length; i++) {
    fns[rest[i]] = function() {
        console.log(rest[i]);
    };
    fns.K();
}

I am new to JavaScript, and don't quite understand how the use of IIFE in the second example results in different behavior. Can someone please clarify?

Nayuki
  • 17,911
  • 6
  • 53
  • 80
redandblue
  • 750
  • 1
  • 5
  • 13

3 Answers3

2
var rest = "KLMNOPQRSTUVWXYZ".split(""), fns = {};
for (var i=0; i<rest.length; i++) {
    (function(i){
        //the i inside this function is private, it is not the same i from outside, 
       //Any modification to the i from the loop won't affect this one.
        fns[rest[i]] = function() {
            console.log(rest[i]);
        };
        fns.K(); 
        // fns[rest[i]](); You should use this if for printing the correct letter
    })(i);
}

No IIFE

var rest = "KLMNOPQRSTUVWXYZ".split(""), fns = {};
for (var i=0; i<rest.length; i++) {
    fns[rest[i]] = function() { //You declare a function for each letter
        console.log(rest[i]); //This i contains always the current iteration from the loop
    };
    fns.K(); //calls the first function defined, "K" that prints the current  iteration
}
Marcos Casagrande
  • 37,983
  • 8
  • 84
  • 98
2

The question you asked actually elucidates the topic of function scope in JavaScript. It has nothing to do with for loops.

Even though JavaScript uses block syntax, scope is determined by functions. In this case, there are two i variables. One is inside the function and one is outside of it.

var rest = "KLMNOPQRSTUVWXYZ".split(""), fns = {};
for (var i=0; i<rest.length; i++) {
    (function(i){
        //the i inside this function is private because of function scope
        fns[rest[i]] = function() {
            console.log(rest[i]);
        };
        fns.K(); 
    })(i);
}
Nice-Guy
  • 1,457
  • 11
  • 20
1

In the first case, the IIFE will create a local scope on each iteration. i resolve to whatever i was passed in the IIFE. Hence, calling fns.K() will always resolve to rest[0].

In the second case, i is bound to the loop's i. Calling fns.K() will log rest[i] where i is the current value i.

Joseph
  • 117,725
  • 30
  • 181
  • 234
  • When the function is being defined, rest[i] is actually not evaluated. It is evaluated during the execution of the function. And then it retrieves the i from the private function scope, if there is one? Am I right? – redandblue Sep 30 '15 at 02:14
  • @user2383728 Yes. In the first case, `i` was encountered first in the IIFE scope. The second case, it's the loop's `i`. – Joseph Sep 30 '15 at 02:15