【问题标题】:JavaScript Variable Scope [duplicate]JavaScript 变量范围 [重复]
【发布时间】:2010-12-07 11:44:56
【问题描述】:

我的一些 JavaScript 代码有问题。

脚本

setTimeout(function() {
    for (var i = 0; i < 5; i++) {
        setTimeout(function() {
            console.log(i);
        }, i * 200);
    }
}, 200);

输出

5、5、5、5、5 而不是 1、2、3、4、5

我可以理解为什么这不起作用,但我想知道是否有人可以向我解释发生了什么以及为什么它不起作用!

另外,如何解决这个范围问题?

【问题讨论】:

    标签: javascript loops closures scope


    【解决方案1】:

    因为您在 set timeout 中使用的所有函数中都访问相同的变量 i。 setTimeout 函数将函数设置为将来在与 i 变量相同的线程上触发毫秒数。 i 值不会复制到函数中,函数在触发时引用实际变量 i。因为您已经遍历父函数直到 i = 5,并且这是在其他任何东西有机会触发之前完成的,所以它们都显示为 5。

    【讨论】:

      【解决方案2】:

      看看this question。它可能会帮助您更好地理解范围和闭包,这与您的问题非常相似。

      【讨论】:

      • 感谢伟大的链接!它完美地解释了它!
      【解决方案3】:

      变量i存在于外部函数的作用域内。

      随着循环的运行而变化。

      内部函数引用它。

      试试这样的:

      var i_print_factory = function (value) {
        return function () {
          console.log(value);
        };
      };
      
      var init_timers = function () {
        for (var i = 0; i < 5; i++) {
          setTimeout(i_print_factory(i), i * 200);
        }
      };
      
      setTimeout(init_timers, 200);
      

      【讨论】:

        【解决方案4】:

        您正在尝试创建一个包含变量“i”的闭包。但是闭包只在函数的末尾创建。因此,如果您的函数是在 for 循环中创建的,它们都将具有上次迭代的值。

        您可以使用以下方法修复它:

        var createFunction = function(index) {
          return function() {
            console.log(index);
          }
        };
        
        for (var i = 0; i < 5; i++) {
          setTimeout(createFunction(i), i * 200);
        }
        

        从另一个函数返回函数的位置。

        【讨论】:

          【解决方案5】:

          setTimeout 回调函数是异步执行的,所有的console.log 调用都指向同一个i 变量,并且在它们执行时,for 循环已经结束 i 包含 4 个。

          您可以将内部 setTimeout 调用包装在接受参数的函数中,以便存储对所有正在迭代的 i 值的引用,如下所示:

          setTimeout(function() {
              for (var i = 0; i < 5; i++) {
                (function (j) { // added a closure to store a reference to 'i' values
                  setTimeout(function() {
                      console.log(j);
                  }, j * 200);
                })(i); // automatically call the function and pass the value
              }
          }, 200);
          

          查看我对以下问题的回答了解更多详情:

          【讨论】:

          • 感谢您的回复以及您对其他问题的回答!它完美地解释了这一切!
          • @Bisbo:不客气,很高兴为您提供帮助!
          • @bdukes:回滚编辑,i 的最后一个值是4,注意 for 循环中的i &lt; 5 条件。
          • i 将是 5 - 这是终止循环的值(也是 OP 报告的值)
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-12-28
          • 1970-01-01
          • 2014-03-28
          • 2021-12-04
          • 2014-09-17
          • 2013-06-12
          相关资源
          最近更新 更多