3

The following snippet is from "Example 5" from this thread on JS and closure. Alternatively, this other thread sort of gets at what I'm curious about.

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

function testList() {
    var fnlist = buildList([1,2,3]);
    for (var j = 0; j < fnlist.length; j++) {
        fnlist[j]();
    }
}

The thread this snippet is from says the output is: "item3 undefined"x3. I understand why "item3" is printed all three times, but I don't understand why list[i] is undefined.

My Question: since list is a parameter of buildList, does that mean it's not a part of the closure of the anonymous function within result.push? If there were a variable within buildList (otherList) which was set to list (and the anonymous function used otherList[i]), would otherList[i] be in the closure? (Therefore instead of "item3 undefined"x3, the output would be "item3 3"x3).

Community
  • 1
  • 1
  • 1
    It's not the list that's making it do that--it's the value of `i`. Actually, if you understand why `"item3"` is printed all three times, you understand why `list[3]` is `undefined`. So I suspect you actually don't ;) – Dave Newton Nov 07 '15 at 19:11
  • Possible duplicate of [JavaScript closure inside loops – simple practical example](http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – Andreas Nov 07 '15 at 19:15
  • 2
    In fact it does alert `item2` three times. – Bergi Nov 07 '15 at 19:31
  • I mistook 3 for the final index (2) because i was too bogged down in figuring out closure to "do the math" on the loop. Lesson learned. Although i still would have wondered my question. – Alex DeForge Nov 07 '15 at 22:38

1 Answers1

0

It has three elements, so maximum valid index is 2. So it is not printing item3 undefined it is item2 undefined.

Reason :

Since you know that the function is printing item-2 string each time because, the function was bounded to the reference, not the value. (This can be avoided using Immediate invoking functions).

But the loop stops/halts, when i cross the i < array.length, So the last updated value of i is now 3 and array[1, 2, 3] at index 3 is undefined. Hence you are seeing undefined value.


Verification:

add console.log as shown below

    for (var i = 0; i < list.length; i++) {
        var item = 'item' + i;
        result.push( function() {
             console.log(i);              //Prints 3 for all 3 invocation.
             alert(item + ' ' + list[i])
        } );
    }
rajuGT
  • 6,224
  • 2
  • 26
  • 44
  • I understand. Does this mean function parameters are in fact able to be part of a closure? – Alex DeForge Nov 07 '15 at 19:19
  • Yes. That is how you can access `list` parameter in `function() {alert(item + ' ' + list[i])}` is accessible. Just try making `list.length` to `list.length - 1` you may get more clarity. (but the result is not the same, just to play around to understand better). – rajuGT Nov 07 '15 at 19:23