【问题标题】:JavaScript Closure Issue... Scoping?JavaScript 关闭问题...范围?
【发布时间】:2013-01-31 07:01:38
【问题描述】:

我正在尝试通过学习如何使用闭包来扩展我的 JavaScript 技能水平。在下面的代码中,我想我会看到 console.log 输出从 3 倒数到 0。相反,我得到 -1、-1、-1、-1。

我知道我正在处理范围界定问题,但仅此而已。少了什么东西?这应该如何正确写,为什么?

function closure_count_test (number)   
{    
    for (var x = 0; x <= number; x += 1)   
    {  
        setTimeout(function() {console.log(number - x);}, x * 1000);  
    }  
}  

closure_count_test(3); 

【问题讨论】:

标签: javascript closures


【解决方案1】:

你的逻辑是正确的。问题是 setTimout 只考虑变量的最新值。所以 setTimout 总是得到 x = 0,因为它是循环中的最后一个。

如果你删除 setTimout 函数,你可以看到你想要的输出。

【讨论】:

  • setTimeout 中的代码只“考虑”变量的当前值;它恰好是在循环的最后一次迭代期间最后设置的值。
【解决方案2】:

xfor 循环迭代,但setTimeout 中的函数使用变量x,该变量在创建函数时没有被插值。这会导致它使用x 的最终值(因为setTimeouts 在循环完成后执行)。

为了解决这个问题,您必须将 x 的值原样传递给setTimeout 的回调。你可以调用一个返回另一个函数的函数(新的回调):

for (var x = 0; x <= number; x += 1) {
    setTimeout(
        (function (x) {
            return function () { console.log(number - x) };
        })(x)
    , x * 1000);  
}

这会将x 从外部范围及其当前值传递到内部范围。内部函数使用创建函数时的任何值 x

返回一个函数以与setTimeout 一起正常工作。

http://jsfiddle.net/ExplosionPIlls/QhA3a/

【讨论】:

    【解决方案3】:

    作用域的基本工作原理是,它使主函数的变量,在嵌套函数中引用的变量在函数结束后保留​​,所有这些函数都可以在以后访问它们。 在提供的示例中,x 是在主函数中定义的变量,所有嵌套函数稍后都可以引用它。到那时 x 的值将是 number+1,所以你的结果很有意义。要解决此问题,您必须避免引用主函数的变量。这是正常的技术:

    function closure_count_test (number)   
    {    
       for (var x = 0; x <= number; x += 1)   
       {  
           setTimeout(function(x) {
              return function() {console.log(number - x);}
           } (x), x * 1000);
       }  
    }
    

    您在这里所做的是调用多个嵌套函数,它们将自己的 x 作为参数复制,并且每个函数都有一个嵌套函数,该函数将通过作用域引用该参数。

    【讨论】:

      【解决方案4】:

      这是可行的,因为 x 被定位在另一个闭包内

      function closure_count_test(number) {
          for (var x = 0; x <= number; x++)  ( // not need {} as here is only one operator
            function (x) { //Now x - local variable in anonymous function
              return setTimeout(function () {
                  console.log(number - x);
              }, x * 1000);
            }(x) // pass x to anonymous function as argument
          ); 
      }
      
      closure_count_test(3);
      

      【讨论】:

      • 这不起作用,因为 1) console.log立即 发生,2) setTimeout 将作为回调传递 undefined。 (我没有投反对票,但这就是为什么这个答案是错误的。)
      猜你喜欢
      • 2010-11-05
      • 2013-02-17
      • 1970-01-01
      • 2011-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多