2013-08-26 99 views
5

至少是我认为它发生在这种情况下:的JavaScript的setTimeout不能访问功能的可调

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变量不无障碍。为什么以及如何修复它?

+0

这是一个非常常见的错误,请参阅此问题:http://stackoverflow.com/questions/5226285/settimeout-in-a-for-loop-and-pass-i-as-value –

+1

不,意思是人们[i]'没有被定义。如果'people'不在范围内,则会出现'Uncaught ReferenceError:人员未定义'之类的内容。 –

回答

21

其实数组还行。它发生的是你的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你传递一个函数给它。这个函数将来会被调用,你在那里做的事情也会在将来被执行。在那一刻(未来的),你的我不再是0或1.它实际上是2,因为你的循环结束了。提供的解决方案使用额外的闭包来创建一个范围/上下文。一旦传递给setTimeout的函数被调用,它就会查找一个i变量。在它的范围内没有这样的事情,所以它上升一级。而且还有我们需要的实际价值。

+0

小心解释解决方案?它是什么?为什么它解决了这个问题? –

+0

编辑的答案。 (我不确定我解释得不够好)。 – Krasimir

+0

差不多。即使您添加了函数调用,函数是否为闭包也无关紧要。唯一重要的是该函数被执行并通过它创建一个新的范围。 –