2

I'm reading an article on how closures work. I'm understanding almost all of it except for Section 5 in that article.

It's talking about how closures work with loops with this example:

function buildList(list) {
  var result = [];
  for (var i = 0; i < list.length; i++) {
    var item = 'item' + list[i];
    result.push( function() {alert(item + ' ' + list[i])} );
  }
  return result;
}

function testList() {
  var fnlist = buildList([1,2,3]);
  // using j only to help prevent confusion - could use i
  for (var j = 0; j < fnlist.length; j++) {
    fnlist[j]();
  }
}

testList();

Three alerts come up, each saying item3 undefined. I do understand why it says item 3. The closure from the buildList function holds a reference to item, it doesn't hold the actual value.

What I don't get is why list[i] comes back as undefined in each alert from the result.push... line. Doesn't that closure still have the list parameter from retained?

inthenameofmusik
  • 617
  • 1
  • 4
  • 16
  • Possible duplicate of [JavaScript closure inside loops – simple practical example](http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – Thilo May 03 '16 at 02:14

2 Answers2

6

Doesn't that closure still have the list parameter from retained?

Yes. But the value of i will be equal to list.length and list[list.length] is undefined. If an array has length 3, then the highest accessible index is 2, not 3:

var arr = [1,2,3];
console.log(arr[2]); // 3
console.log(arr[3]); // undefined

Related: JavaScript closure inside loops – simple practical example

Community
  • 1
  • 1
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • The value of `i` is list.length *after the loop has run its course* (which it has, by the time you invoke the closure). – Thilo May 03 '16 at 02:13
1

buildList and it's inner, anonymous function share context to a certain degree. Changing i, as is done in the for loop, changes it for all the created anonymous functions that are created even after the fact. Change the anonymous function from:

function() {alert(item + ' ' + list[i])}

to something like:

(function(i){return function() {alert(item + ' ' + list[i]);};})(i)

This causes a copy of i's value to be made at the time of creation and assigned into another, different i that overrides the outer i in the context of the returned anonymous function, while still allowing dynamic access to item and list.

Ouroborus
  • 16,237
  • 4
  • 39
  • 62