1

What is the difference between these functions? Why does the first one work and the second does not work as expected?

http://jsfiddle.net/GKDev/x6pyg/ (this works)

http://jsfiddle.net/GKDev/bv4em/ (and this is not)

I'm trying to loop over input elements and add onfocus events on them:

for (var i = 0; i < helpText.length; i++) {
    var item = helpText[i];

    document.getElementById(item.id).onfocus = function() {
        showHelp(item.help);
    };
}
Trott
  • 66,479
  • 23
  • 173
  • 212
Givi
  • 1,674
  • 2
  • 20
  • 35
  • possible duplicate of [Javascript closure inside loops - simple practical example](http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – bfavaretto Mar 28 '13 at 22:33

3 Answers3

2

In your non-working example, when the anonymous function is called, item has the last value it held when the for loop finished executing. That's because this variable belongs to the parent function that contains the for loop.

In your working example, you create a new function, pass in the current value of item like so:

function (help) {
            return function () {
                showHelp(help); // <-- This will be the value enclosed in this anonymous function
            };
        }(item.help); // <-- Calls an anonymous function passing in the current value

This creates a new closure around that value as it existed during that iteration. When the anonymous function is called, it uses that local value.

Mike Christensen
  • 88,082
  • 50
  • 208
  • 326
2

It is treated as:

var item;

for (var i = 0; i < helpText.length; i++) {
    item = helpText[i];

    document.getElementById(item.id).onfocus = function() {
        showHelp(item.help);
    };
}

The loop has finished before any focus callback fires and at that point item is the last item assigned.

Esailija
  • 138,174
  • 23
  • 272
  • 326
1

It is pretty easy in fact.

In the first case you are passing item.help inside of the closure, which acts as a local copy. It's like a prisoner of its scope. What happens outside, nobody cares.

for (var i = 0; i < helpText.length; i++) {
        var item = helpText[i];
        document.getElementById(item.id).onfocus = function (help) {
            return function () {
                showHelp(help);
            };
        }(item.help);
    }

In the second one, there is no closure preserving the value of item, which means that when item is evaluated, it evaluates to its actual value, i.e.: the last element of the array, since the last loop of the for set its value to the last value of the array.

for (var i = 0; i < helpText.length; i++) {
    var item = helpText[i];
    document.getElementById(item.id).onfocus = function() {
      showHelp(item.help);
    }
  }
bgusach
  • 14,527
  • 14
  • 51
  • 68