var animel = new Array();
animel[0] = 'cat';
animel[1] = 'dog';
animel[2] = 'horse';
animel[3] = 'cow';
animel[4] = 'elephant';
animel[5] = 'tiger';
animel[6] = 'lion';
animel[7] = 'fish';
for (var i = 0; animel.length > i; i++) {
setTimeout( function () {
console.log(animel[i]);
}, 2000);
}
当我在控制台中执行此代码时,它会记录undefined
而不是元素的名称。我在这做错了什么?
答案 0 :(得分:3)
一个非常常见的问题:回调是异步执行的,但使用的最后一个设置值为i
。事件链是:
i
的值为8
console.log(animel[i])
,其中i
为8
为避免您需要断开与i
:
setTimeout((function (index) {
return function () { console.log(animel[index]); }
})(i), 2000);
答案 1 :(得分:2)
setTimeout
内的函数引用相同的i
值。因此,对于每一个,i
都是8
。
您需要创建一个闭包来“捕获”i
值。
var createFunc = function(i){
return function(){
console.log(animel[i]);
};
};
for (var i = 0; animel.length > i; i++) {
setTimeout(createFunc(i), 2000);
}
答案 2 :(得分:2)
数组没有问题,问题是你如何关闭变量i
。
当函数执行时(循环完成后2秒),i
增加超出animel
的范围。简单的解决方案是提供i
到setTimeout
的当前值,并将其作为函数中的参数接收,如下所示:
for (var i = 0; animel.length > i; i++) {
setTimeout(function (i) {
console.log(animel[i]);
}, 2000, i);
}
如果你需要在IE上支持这种语法< 9,MDN article提供了几种polyfill技术。
答案 3 :(得分:1)
这是一个JS机箱候选者。 i
范围中使用的setTimeout
的值不是您在使用时所考虑的值。要在超时发生时强制使用i
的实际值,可以使用i
作为常量而不是迭代器的方式使用它周围的空间。
for (var i = 0; i<animel.length; i++) {
(function(x){
setTimeout(function() {
console.log(animel[x]);
}, 500);
})(i);
}
答案 4 :(得分:0)
你将它包装在一个setTimeout函数中,这是一个非阻塞操作。当循环完成时,我已经增加到一个破坏循环的值,并且超出了数组的范围。