循环中的javascript var声明

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了循环中的javascript var声明相关的知识,希望对你有一定的参考价值。

/*Test scope problem*/
for(var i=1; i<3; i++){
    //declare variables
    var no = i;
    //verify no
    alert('setting '+no);

    //timeout to recheck 
    setTimeout(function(){
        alert('test '+no);
    }, 500);
}

它按预期警告“设置1”和“设置2”,但在超时后它输出“测试2”两次 - 由于某种原因,变量“否”在第一次循环后没有重置......

我发现只有一个“丑陋”的解决方法:

/*Test scope problem*/
var func=function(no){
    //verify no
    alert('setting '+no);

    //timeout to recheck 
    setTimeout(function(){
        alert('test '+no);
    }, 500);
}
for(var i=1; i<3; i++){
    func(i);
}

有关如何以更直接的方式解决此问题的任何想法?或者这是唯一的方法吗?

答案

javascript没有块范围,并且提升了变量声明。这些事实共同意味着您的代码相当于:

var no;

/*Test scope problem*/
for(var i=1; i<3; i++){
    //declare variables
    no = i;
    //verify no
    alert('setting '+no);

    //timeout to recheck 
    setTimeout(function(){
        alert('test '+no);
    }, 500);
}

当你的超时函数执行时,循环结束很长时间,no保持其最终值为2。

解决这个问题的方法是将no的当前值传递给一个函数,该函数为每次调用setTimeout创建一个新的回调。每次创建一个新函数意味着每个setTimeout回调都绑定到具有自己的变量集的不同执行上下文。

var no;

/*Test scope problem*/
for(var i=1; i<3; i++){
    //declare variables
    no = i;
    //verify no
    alert('setting '+no);

    //timeout to recheck 
    setTimeout( (function(num) {
            return function() {
                alert('test '+num);
            };
        })(no), 500);
}
另一答案

这与您的修复基本相同,但使用不同的语法来实现范围调整。

/*Test scope problem*/
for (var i = 1; i < 3; i++) {
  //declare variables 
  var no = i;
  //verify no 
  alert('setting ' + no);

  //timeout to recheck
  (function() {
    var n = no;
    setTimeout(function() { 
      alert('test ' + n);
    }, 500);
  })();
} 
另一答案

Javascript没有词法作用域(for-loop不会创建新的作用域),您的解决方案是标准的解决方法。另一种写这个的方法可能是:

[1, 2].forEach(function(no){
    //verify no
    alert('setting '+no);

    //timeout to recheck 
    setTimeout(function(){
        alert('test '+no);
    }, 500);
})

forEach()是在ECMAScript 5中引入的,并且存在于现代浏览器中但不存在于IE中。您可以使用my library来模拟它。

另一答案

我喜欢我可以从this answer获得如此多的里程数。

如果您需要帮助来应用该答案,请告诉我。

编辑

当然。我们来看看你的原始代码。

//timeout to recheck 
setTimeout(function(){
    alert('test '+no);
}, 500);

看到那个匿名函数?你传递给setTimeout()的人?直到定时器这样说才会调用它 - 在循环退出后500ms就好了。

您希望的是no“就地”进行评估,但不是 - 它在调用函数时进行评估。到那时,no是2。

为了解决这个问题,我们需要一个在循环迭代期间执行的函数,它本身将返回一个setTimeout()可以按照我们期望的方式使用的函数。

setTimeout(function( value )
{
  // 'value' is closed by the function below
  return function()
  {
    alert('test ' + value );
  }
}( no ) // Here's the magic
, 500 );

由于我们创建了匿名函数并立即调用它,因此创建了一个新的作用域,我们可以在其中关闭变量。而且这个范围围绕value,而不是no。由于value为每个循环收到一个新的(咳咳)值,这些lambdas中的每一个都有它自己的值 - 我们想要的那个。

因此,当setTimeout()触发时,它正在执行从闭包函数返回的函数。

我希望能够解释它。

以上是关于循环中的javascript var声明的主要内容,如果未能解决你的问题,请参考以下文章

请问微信小程序let和var以及const有什么区别

JavaScript“for-in”循环中的“var”还是没有“var”?

JavaScript - 在 for 循环中使用 let 和 var 关键字声明迭代变量有啥区别? [复制]

js中的函数提升和变量提升

varletconst区别

微信小程序var和let以及const的区别: