2

I've been reading a book about JavaScript and the author has been touching the subject of closures for a few pages. On one page, he shows the following example:

function wrapElements(a) {
  var result = [], i, n;
  for (i = 0, n = a.length; i < n; i++) {
    result[i] = function() { return a[i]; };
  }
  return result;
}

var wrapped = wrapElements([10, 20, 30, 40, 50]);
var f = wrapped[0];

Now, he says that one might expect f(); to return 10, but it actually returns undefined.

Here's what he says:

The bug in the program comes from the fact that the programmer apparently expected the function to store the value of i at the time the nested function was created. But in fact, it contains a reference to i. Since the value of i changes after each function is created, the inner functions end up seeing the final value of i. [...] Since each iteration of the loop increments i until it runs off the end of the array, by the time we actually call one of the closures, it looks up index 5 of the array and returns undefined.

But I just can't get my head around his explanations. I've read again his previous explanations about closures (and think I understand them -- but obviously, it seems like I don't) and I've searched for more information on closures on the Internet. I stil can't understand why f(); would return undefined.

Wouldn't the anonymous function be created and called at each iteration of the loop; and therefore, wouldn't it look up all indexes and not just index 5? Or am I misunderstanding something?

Can anyone help me out? Thanks.

Pascal Bergeron
  • 761
  • 3
  • 12
  • 27

1 Answers1

2

All the little functions created in the loop share that common variable i. What's the value of i when the for loop finishes? 5.

When the functions are called, i is still 5, and a[5] is undefined.

Here's the loop that creates the functions:

  for (i = 0, n = a.length; i < n; i++) {
    result[i] = function() { return a[i]; };
  }

Each function created contains a reference to i, and means "return the array element corresponding to the current value of i", where current means current at the time the function is actually called. JavaScript doesn't retain some "frozen" state for such functions, it retains the actual scope from the enclosing function. In that scope, the variable i is still its same old jolly self, and will be 5 whenever any of the functions created in the loop inquire as to its value.

Pointy
  • 405,095
  • 59
  • 585
  • 614