好吧,首先是堆栈溢出问题。我希望我做得对。
我正在尝试运行此代码:
for(var i = 1; i < 17; i++){
console.log("for loop runs. i is " + i);
setTimeout(function(){
console.log("setTimeout runs. i is " + i);
if(i < 3){
$( ".example1" ).append( i );
$( ".example2" ).append( i );
$( ".example3" ).append( i );
$( ".example4" ).append( i );
$( ".example5" ).append( i );
}
else if(i<5){
$( ".example1" ).append( i );
$( ".example2" ).append( i );
$( ".example3" ).append( i );
$( ".example5" ).append( i );
}
else if(i<11){
$( ".example1" ).append( i );
$( ".example2" ).append( i );
$( ".example3" ).append( i );
}
else if(i<15){
$( ".example1" ).append( i );
$( ".example3" ).append( i );
}
else if(i<17){
$( ".example1" ).append( i );
}
},200);
} //end for loop
我在控制台中收到了这个输出:
for loop runs. i is 2
for loop runs. i is 3
for loop runs. i is 4
for loop runs. i is 5
for loop runs. i is 6
for loop runs. i is 7
for loop runs. i is 8
for loop runs. i is 9
for loop runs. i is 10
for loop runs. i is 11
for loop runs. i is 12
for loop runs. i is 13
for loop runs. i is 14
for loop runs. i is 15
for loop runs. i is 16
(16) setTimeout runs. i is 17 // <---- runs 16 times
因此for
循环运行并增加到17,然后setTimeout
运行16次。我不明白这里发生了什么。
答案 0 :(得分:1)
解决方案: setTimeout
执行
可变关闭问题。 IIFE救援:
for(var i = 1; i < 17; i++){
console.log("for loop runs. i is " + i);
(function (ii) {
setTimeout(function(){
console.log("setTimeout runs. ii is " + ii);
// the rest of your code goes here
},200);
}(i));
}
说明:
您获得价值的原因&#34; 17&#34;对于i
,因为在setTimeout
执行时,i
已被赋值为&#34; 17&#34;使用for
循环的最后一次迭代。 (i
已将设置为&#34; 17&#34;以便循环终止。)当您将i
传递给{{1你提供setTimeout
,而不是 i
的当前值的功能。
变量范围由它们在执行该函数时实例化的函数(i
&d; d)决定。准备好var
循环后i
(自动)var
。那么什么&#34;功能&#34; for
循环是否存在? for
或全球范围。这是window
的范围。这就是i
在触发时获取setTimeout
值的地方。
因此,为了解决这个问题,我们需要在函数中实例化一个变量并执行该函数,以便在执行程序时锁定该变量的值。
从概念上讲,首先,使用一个或多个参数编写一个函数:
i
执行此函数时, function (x, y, z) {
// stuff here
};
,x
和y
会在此函数范围内获取var。
其次,执行函数,传递必要的参数:
z
function (x, y, z) {
// stuff here
}(a, b, c);
,a
和b
已经存在,可能在全局范围内,现在您将其当前值传递给此函数作为参数。
第三,将函数包装在括号中,以便JavaScript解释器将其视为function expression and not a function declaration。
c
顺便说一下,这也有效:
(function (x, y, z) {
// stuff here
}(a, b, c));
...与!function (x, y, z) {
// stuff here
}(a, b, c);
,~
和+
一样。你只需要在行的开头使用一些良性操作符来将JS从它的函数声明狂热中剔除。
有点像-
循环,函数执行时函数参数变量会自动for
,但在这种情况下,范围在此函数本身内。因此,在该代码行中执行时var
的值将传递给IIFE函数内的新变量i
并锁定到该函数范围。现在,当ii
最终准备好执行时,它会查找该函数范围,而不是 global ,以获取该值。
答案 1 :(得分:0)
阅读有关javascript中的闭包的更多信息。这里发生的是在for循环内创建多个函数(闭包),共享相同的环境。到调用setTimeout函数时,循环完成迭代,i变量总是设置为17。
了解更多here
答案 2 :(得分:0)
for循环运行16次,i = 1到16(如预期的那样)。 你的setTimeout也会运行16次,因为它在循环中同样运行。
因为你的setTimeout函数在200毫秒后运行,但循环的16次迭代在该时间的一小部分内运行,所有setTimeouts在循环结束后很长时间运行,当时我已经设置为17。