Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript setTimeout can't access function variable [duplicate]

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?

like image 231
ali Avatar asked Aug 26 '13 13:08

ali


1 Answers

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.

like image 144
Krasimir Avatar answered Oct 19 '22 23:10

Krasimir