javascript - 奇怪的 JavaScript 代码执行顺序

标签 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));
}
<小时/>

说明:

您获得 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
};
执行此函数时,

xyz 在此函数范围内获得 var'd。

其次,执行函数,传递必要的参数:

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

abc 已经被 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/

相关文章:

javascript - Jquery getJson 请求被取消

javascript - Gulp JavaScript 文件过滤,无需其父文件夹

javascript - 这是否符合 "arrow function"实现的条件?

javascript - Electron 菜单中是否可以有子菜单的子菜单?

javascript - Gulp 任务在无限循环中运行

PHP、MYSQL 选择框选择不正确

javascript - 通过数组中每个 JSON 对象中的值从 JSON 数组中删除重复项

JavaScript XML-RPC 调用未执行

javascript - 拆分以@符号开头的多个单词

javascript - 使用 QUnit/Sinon 测试 window.onerror