JavaScript关闭问题......范围?

时间:2013-01-31 07:01:39

标签: javascript closures

我正在尝试通过学习如何使用闭包来扩展我适度的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); 

4 个答案:

答案 0 :(得分:0)

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

如果删除setTimout函数,则可以看到所需的输出。

答案 1 :(得分:0)

这是有效的,因为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);

答案 2 :(得分:0)

如何在基本单词中使用作用域,它使得嵌套函数中引用的主函数的变量在函数结束后保留​​,并且所有这些函数可以在以后访问它们。 在提供的示例中,x是在main函数中定义的变量,并且所有嵌套函数稍后将能够引用它。到那个时候,x的值将是数字+ 1,所以你的结果很有意义。要解决此问题,必须避免引用main函数的变量。这是正常的技术:

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作为参数复制,并且每个嵌套函数都有一个嵌套函数,它将通过作用域引用该参数。

答案 3 :(得分:0)

<{>} xfor循环迭代,但setTimeout中的函数使用变量x,该变量在创建函数时未进行插值。这导致它使用x的最终值(因为setTimeout在循环完成后执行)。

为了解决这个问题,你必须将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/