奇怪的JavaScript代码执行顺序

安斯利

好吧,第一个堆栈溢出问题。我希望我做对了。

我正在尝试运行以下代码:

    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));
}

解释:

之所以要获取值“ 17”,i是因为在setTimeout执行s时,ifor循环的最后一次迭代中为其分配了值“ 17” i 必须将其设置为“ 17”,循环才能终止。)当您处理isetTimeout函数时,将为其提供引用i而不是的当前值i

变量作用域由在函数var执行时和执行时被实例化的函数('d)确定。ivar在准备for循环自动(自动)完成那么,for循环存在于什么“功能”中呢?window,或全球范围。那是范围i那就是setTimeout去获取i何时触发的价值

因此,要解决该问题,我们需要在函数中实例化一个变量并执行该函数以在程序执行的那一刻锁定该变量的值。

从概念上讲,首先,编写一个具有一个或多个参数的函数:

function (x, y, z) {
  // stuff here
};

x,,yz在执行此函数时在此函数范围内获取var'd。

其次,执行功能,并传递必要的参数:

function (x, y, z) {
  // stuff here
}(a, b, c);

abc可能已经在全局范围内更改了,现在您要将它们的当前值作为参数传递给此函数。

第三,将函数包装在括号中,以便JavaScript解释器将其视为函数表达式而不是函数声明

(function (x, y, z) {
  // stuff here
}(a, b, c));

顺便说一句,这也有效:

!function (x, y, z) {
  // stuff here
}(a, b, c);

...一样~+-您只需要在行的开头添加一些良性运算符,即可将JS甩出函数声明狂热的状态。

就像for循环一样,函数参数变量在var执行函数时会自动生成,但是在这种情况下,作用域在此函数本身之内。因此,价值i在执行该行代码瞬间被传递给新变量ii的IIFE函数内部,并锁定在该函数范围内。现在,当setTimeout最终准备好执行时,它会寻找该功能范围而不是全局范围来获取值。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章