0

So i already learnt a lot about closures here on SO.

But i still found one examples i can't explain to myself:

       function buildList(list){
            var result = [];
            for(var i = 0; i < list.length; i++) {
                var item = "item: " + list[i] + " i's value: " + i;  //i has the value of 2 here, but why?
                result.push( function(){document.write(item + ", list[i]:" + list[i] + ", i's value in the anonymous function:" + i + "<br>")});
            } //i = 3 here
            return result;
        }

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

        testList();

As i would expect of the closure, i should be 3 when i execute the testList().

But the result is:

item: 3 i's value: 2, list[i]:undefined, i's value in the anonymous function:3

item: 3 i's value: 2, list[i]:undefined, i's value in the anonymous function:3

item: 3 i's value: 2, list[i]:undefined, i's value in the anonymous function:3

Why does is i for the var item => 2 and i inside the anonymous function => 3 ? As i read, closures create new execution environments, but shouldnt i be the same value for the closure?

EDIT

This is not a duplicate of JavaScript closure inside loops – simple practical example, i don't want to know, how to create a new execution environment.

I want to know why the value of the same variable i (of the the loop) differs in the same scope?

Community
  • 1
  • 1

1 Answers1

0

When you adding your new function to result list it's holding reference to item variable and i counter. During the loop inside buildList function you aren't creating few item variables, but you are overwriting existing one, at the end of buildList function execution values of item and i variables looks like this:

  • 3
  • "item: 3 i's value: 2"

And list[i] is undefined because your list length is 3, you don't have list[3] item. So when you are calling your anonymous function from loop in testList it's retrun you exact same values as item and i variables keep. Also create anonymous functions in loops it's not the best practice, I would suggest you to modify your buildList function like this:

function buildList(list) {
    var index = 0;

    return function () {
        if (index >= list.length) return
        var item = "item: " + list[index] + " i's value: " + index;
        document.body.innerHTML += [
          item, ", list[i]:", list[index], 
          ", i's value in the anonymous function:",
          index, "<br>"
        ].join('')
        index++
    }
}

function testList() {
    var list = [1, 2, 3];
    var testTheList = buildList(list);
    document.body.innerHTML = '';
    for (var j = 0; j < list.length; j++) {
        testTheList();
    }
}

testList();
krasu
  • 2,037
  • 23
  • 22
  • Aaaaah! Thanks i finally got the one with item and i. Already knew the other points, but somehow was stuck with overwriting the "item". – Straighter Jul 16 '15 at 09:55