关于javascript:为什么Array在控制台中不起作用?

Why Array doesn't work in console?

本问题已经有最佳答案,请猛点这里访问。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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而不是元素的名称。 我在这做错了什么?


一个非常常见的问题:回调是异步执行的,但使用的是i的最后一个设置值。事件链是:

  • 你的循环设置了一些超时
  • 循环结束,i的值为8
  • 触发超时,并执行console.log(animel[i]),其中i8

为避免这种情况,您需要断开与i的闭包连接:

1
2
3
setTimeout((function (index) {
    return function () { console.log(animel[index]); }
})(i), 2000);


数组没有问题,问题是如何关闭变量i

当函数执行时(循环完成后2秒),i已递增超出animel的界限。简单的解决方案是提供isetTimeout的当前值,并将其作为函数中的参数接收,如下所示:

1
2
3
4
5
for (var i = 0; animel.length > i; i++) {
    setTimeout(function (i) {
        console.log(animel[i]);
    }, 2000, i);
}

如果您需要在IE <9上支持此语法,MDN文章提供了几种polyfill技术。


setTimeout内的函数引用相同的i值。因此对于每一个,i8

您需要创建一个闭包来"捕获"i值。

1
2
3
4
5
6
7
8
var createFunc = function(i){
    return function(){
        console.log(animel[i]);
    };
};
for (var i = 0; animel.length > i; i++) {
    setTimeout(createFunc(i), 2000);
}

这是JS机箱候选者。 setTimeout范围中使用的i的值不是您在使用时所考虑的值。要在超时发生时强制使用i的实际值,可以使用i作为常量而不是迭代器使用它周围的机箱。

1
2
3
4
5
6
7
for (var i = 0; i<animel.length; i++) {
    (function(x){
        setTimeout(function() {
            console.log(animel[x]);
        }, 500);
    })(i);
}

DEMO


你将它包装在一个setTimeout函数中,这是一个非阻塞操作。当循环完成时,我已经增加到一个破坏循环的值,并且超出了数组的范围。