0
<script type="text/javascript">   
function buildList(list) {
  var result = [];
  for (var i = 0; i < list.length; i++) {
    var item = 'item' + list[i];
    result.push( function() {console.log(item + ' ' + list[i])} );
  }
  return result;
}

function testList() {
  var fnlist = buildList([1,2,3]);
  fnlist[0]();
}
testList(); 
</script>

Question:

IN firefox->console, it shows item3 undefined, why?

user2507818
  • 2,719
  • 5
  • 21
  • 30
  • http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example – goat Jul 03 '13 at 04:05

2 Answers2

0

you can change

result.push( function() {console.log(item + ' ' + list[i])} );

to

result.push( function() {console.log(item + ' ' + list[i] + ' ' + i)} );

then you find that i is 3, you should use clousre to avoid this problem.

  • well, you are right, but I have set condition(`i < list.length`) for loop,:`for (var i = 0; i < list.length; i++)`,if i=3 which is = list.length, should not execute this line: `result.push( function() {console.log(item + ' ' + list[i])} );` so why? – user2507818 Jul 03 '13 at 04:19
0

It is because the evaluation of closure reference happens at the execution time of the statement (item + ' ' + list[i] + ' ' + i, by that time value of i becomes 4, this list[4] returns undefined.

The execution sequence will be, you are creating a closure variable i in the loop, so all the function references pushed to result references the same instance of i, any modification done to the variable will be reflected in each of the added function irrespective of when it was added.

The solution in such a case is to create a private closure inside the loop statement using a iife

Demo: Fiddle

Arun P Johny
  • 384,651
  • 66
  • 527
  • 531
  • there is a solution is that : var tempI = i; result.push( function() {console.log(item + ' ' + list[tempI])} ); – Hung Doan Jul 03 '13 at 04:16
  • @hungdoan, it still will not work as expected because javascript does not have block level scope http://jsfiddle.net/arunpjohny/8mTCn/3/ – Arun P Johny Jul 03 '13 at 04:19
  • well, but the end, `i=3` not `4`, but how come when `i=3`, can still execute this line: `result.push( function() {console.log(item + ' ' + list[i])} );`? I have set the condition `i < list.length`, `list.length=3` – user2507818 Jul 03 '13 at 04:31
  • @user2507818 sorry, i thought you were passing 4 elements, then also the logic holds because `list[3]` is undefined – Arun P Johny Jul 03 '13 at 04:44