好吧,第一个堆栈溢出问题。我希望我做得对。
我正在尝试运行此代码:
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次。我不明白这是怎么回事。
最佳答案
解决方案:执行 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));
}
<小时/>
说明:
您获得 i
值“17”的原因是,在 setTimeout
执行时,i
已经在 for
循环的最后一次迭代中分配值“17”。 (i
必须 设置为“17”才能终止循环。)当您将 i
交给 setTimeout 时
函数,您为其提供对 i
的引用,而不是 i
的当前值。
变量作用域由它们在函数中实例化(var
)的函数以及执行该函数时确定。在准备 for
循环时,i
被(自动)var
化。那么 for 循环存在于什么“函数”中呢? 窗口
,或全局范围。这就是i
的范围。这就是 setTimeout
在触发时获取 i
值的地方。
因此,为了解决这个问题,我们需要在函数中实例化一个变量并执行该函数以在程序执行时锁定该变量的值。
从概念上讲,首先编写一个函数,带有一个或多个参数:
function (x, y, z) {
// stuff here
};
执行此函数时,x
、y
和 z
在此函数范围内获得 var'd。
其次,执行函数,传递必要的参数:
function (x, y, z) {
// stuff here
}(a, b, c);
a
、b
和 c
已经被 var'd(可能在全局范围内),现在您正在传递它们当前值作为参数传递给该函数。
第三,将函数括在括号中,以便 JavaScript 解释器将其视为 function expression and not a function declaration .
(function (x, y, z) {
// stuff here
}(a, b, c));
顺便说一句,这也有效:
!function (x, y, z) {
// stuff here
}(a, b, c);
...~
、+
和 -
也是如此。你只需要在行的开头添加一些良性的运算符来让 JS 摆脱函数声明的疯狂。
有点像for
循环,函数参数变量在函数执行时会自动var
'd,但在这种情况下,作用域在该函数本身之内。因此,该行代码执行时 i
的值被传递给 IIFE 函数内的新变量 ii
并锁定在到该函数范围。现在,当 setTimeout
最终准备好执行时,它会在该函数范围(而不是全局)中获取值。
关于javascript - 奇怪的 JavaScript 代码执行顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29124538/