6

At least is what I think it happens in this case:

function MyFunc() {
    var people = Array({name: 'Alex', age: 25}, {name: 'Ellen', age: 43});
    for (var i=0; i<people.length; i++) {
        setTimeout(function() { ShowIt(people[i].name) }, 1000); // !!!
    }
}

function ShowIt(name) {
    alert(name);
}

I get this error Uncaught TypeError: Cannot read property 'name' of undefined, so it looks like inside the setTimeout listener function the people variable is not accessible. Why and how can I fix it?

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
ali
  • 10,927
  • 20
  • 89
  • 138
  • This is a very common mistake, see this question: http://stackoverflow.com/questions/5226285/settimeout-in-a-for-loop-and-pass-i-as-value – George Aug 26 '13 at 13:31
  • 1
    No, it means that `people[i]` is not defined. If `people` was not in scope, you would get something like `Uncaught ReferenceError: people is not defined`. – Felix Kling Aug 26 '13 at 13:31

1 Answers1

24

Actually people array is ok. What it happens is that your i is actually 2 and there is no third element in the array. That's why you get this error. Here is the solution:

function MyFunc() {
    var people = Array({name: 'Alex', age: 25}, {name: 'Ellen', age: 43});
    for (var i=0; i<people.length; i++) {
        (function(i) {
            setTimeout(function() {             
                ShowIt(people[i].name) 
            }, 1000);
        })(i);
    }
}

function ShowIt(name) {
    console.log(name);
}

MyFunc();

Here is a jsfiddle http://jsfiddle.net/krasimir/XDfLu/2/

The long answer: when you use setTimeout you are passing a function to it. That function is called in the future and the things which you make there are also executed in the future. At that moment (the future one) your i is no longer 0 or 1. It is actually 2 because your loop ended. The provided solution uses additional closure to create one more scope/context. And once the function passed to setTimeout is called it looks for a i variable. There is no such a thing in its scope, so it goes one level up. And there is the actual value which we need.

Krasimir
  • 13,306
  • 3
  • 40
  • 55
  • Care to explain the solution? What is it and why does it solve the problem? – Felix Kling Aug 26 '13 at 13:40
  • Answer edited. (I'm not sure that I explained it well enough). – Krasimir Aug 26 '13 at 13:47
  • Nearly. Even though you added a function call, it doesn't matter whether the function is a closure or not. The only important thing is that the function is executed and creates a new scope through that. – Felix Kling Aug 26 '13 at 14:05