JavaScript的setTimeout无法访问函数变量

6
至少我认为在这种情况下会发生以下事情:
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);
}

我遇到了这个错误Uncaught TypeError: Cannot read property 'name' of undefined,因此在setTimeout监听器函数内部,people变量似乎无法访问。为什么会这样,我该如何解决?


这是一个非常常见的错误,请参考此问题:https://dev59.com/kW435IYBdhLWcg3wxDBp - George
1
不,这意味着 people[i] 没有被定义。如果 people 不在作用域内,你会得到类似于 Uncaught ReferenceError: people is not defined 的错误。 - Felix Kling
1个回答

24

事实上,people数组是正确的。问题出在i实际上为2,并且数组中没有第三个元素。这就是为什么你会得到这个错误。以下是解决方案:

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();

这是一个jsfiddle:http://jsfiddle.net/krasimir/XDfLu/2/

长话短说:当使用setTimeout时,你将一个函数传递给它。该函数在未来被调用,其中包含的内容也会在未来执行。此时(未来的那个时刻),您的i不再是0或1。实际上它是2,因为循环已经结束了。提供的解决方案使用额外的闭包来创建另一个范围/上下文。一旦传递给setTimeout的函数被调用,它会寻找i变量。在其范围内没有这样的东西,所以它向上一级寻找,那里有我们需要的实际值。


能否解释一下解决方案?它是什么,为什么可以解决问题? - Felix Kling
回答已编辑。(我不确定我解释得足够清楚。) - Krasimir
几乎。即使您添加了一个函数调用,无论该函数是否为闭包都没有关系。唯一重要的是执行该函数并通过它创建新的作用域。 - Felix Kling

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接