0

See the code, which explains more than 1000 words. I don't get it, why all 5 created functions always return 5 (last iteration value). I am really interested, what's wrong or what I have missed. I remember dare, Douglas Crockford has talked about this thing, but I didn't find that resource either.

function createFunctions(n) {
    var arrayFunctions = [];

    for (var i=0; i<n; i++) {
        arrayFunctions.push(function() {
            console.log(i);
        });
    }

    return arrayFunctions;
}

var arrayFunctions = createFunctions(5);

arrayFunctions[2]();  // returns 5 instead of 2
arrayFunctions[3]();  // returns 5 instead of 3
arrayFunctions[4]();  // returns 5 instead of 4
appsunited
  • 1,667
  • 16
  • 22
  • possible duplicate of [How do JavaScript closures work?](http://stackoverflow.com/questions/111102/how-do-javascript-closures-work) – Daniel A. White Dec 02 '13 at 23:55
  • You need a closure that creates a new scope where the value of the variable is kept locally – adeneo Dec 02 '13 at 23:56

3 Answers3

3

The functions are closing over the variable, not the value of the variable. This means that they all refer to the i that is defined in the loop and is updating at every iteration. By the time createFunctions returns the loop has completed and i is at its final value (5).

function createFunctions(n) {
    var arrayFunctions = [];

    for (var i=0; i<n; i++) { 
        (function(j) {
            arrayFunctions.push(function() {
                console.log(j);
            });
        }(i));
    }

    return arrayFunctions;
}
adeneo
  • 312,895
  • 29
  • 395
  • 388
Sean
  • 4,450
  • 25
  • 22
1

It is because the functions are holding onto the reference of i, not the value of i.

Daniel A. White
  • 187,200
  • 47
  • 362
  • 445
0

Not sure if it is the best way, but you could create a function that returns a function which stores the correctly scoped variable:

function createFunctions(n) {
    var arrayFunctions = [];
    for (var i=0; i<n; i++) {
        var scopedFunction = function(scopedI) {
            return function() {
                 console.log(scopedI);
            }
        }
        arrayFunctions.push(scopedFunction(i));
    }

    return arrayFunctions;
}

I tested this out in jsfiddle and it appears to give the intended result.

ssawchenko
  • 1,198
  • 1
  • 13
  • 24