11

我确定我已经阅读了关于 SO 的讨论,但找不到。简单地说,在循环声明中声明 for 循环的增量是否有缺点?这有什么区别:

function foo() {
    for (var i=0; i<7; i++) {
        // code
    }
}

...还有这个:

function foo() {
    var i;
    for (i=0; i<7; i++) {
        // code
    }
}

既然 JS 有函数作用域,那应该没问题吧?是否存在前一种方法会导致问题的极端情况?

如果它们是相同的,为什么 Crockford/JSLint 都是“没办法 dawg”?

4

5 回答 5

14

这些是完全相同的。javascript 中的所有局部变量都具有函数作用域,这意味着它们对于声明它们的整个函数都是有效的。起初这通常是反直觉的,因为大多数花括号语言将变量的生命周期限制在声明它们的块中。

一部分 Javascript 开发人员非常喜欢第二种形式。基本原理是,由于所有变量都具有函数作用域,因此您应该在函数级别声明它们,以使生命周期明确,即使对于那些不熟悉 Javascript 的人也是如此。这只是一种风格,绝不是硬性规定

编辑

请注意,随着ES6 let的引入,您现在可以在循环中使用 let 获取真正的块范围变量更多详细信息

for(let i = 1; i <= 5; i++) {
   setTimeout(function(){
       console.log('Value of i : ' + i);
   },100);
}
于 2012-04-18T00:16:53.127 回答
8

var在循环头中声明 with 的问题在于它具有欺骗性。看起来您正在声明一个变量,其范围仅限于for循环,而它实际上存在于函数中的任何地方 - 包括声明之前:

var i = 1;
function foo() {
   console.log(i);                     // 'undefined'
   for (var i=1; i<100; ++i) {
   }
}

即使console.log调用发生在 local 的声明之前i,它仍然在它的范围内,因为它在同一个函数内。因此i,尚未为其分配任何值的 local 是传递给log. 这可能令人惊讶。对于不熟悉 Javascript 范围规则的任何人来说,这肯定不是显而易见的。

ECMAScript 2015开始,有一种更好的方式来声明变量:let. 声明的变量let是包含它们的块的局部变量,而不是整个函数。因此,上述代码的这个版本1将按预期打印:

let i=1; // could use var here; no practical difference at outermost scope
function foo() {
  console.log(i);               // 1
  for (let i=1; i<100; ++i) {
  }
}

因此,现代 Javascript 中的最佳实践是使用let而不是var. 但是,如果您坚持使用 ECMAScript 2015 之前的实现,那么在函数顶部声明所有变量而不是等到第一次使用时会更容易混淆。

于 2012-04-18T00:19:19.700 回答
1

没有区别,但我更喜欢第二种方式(根据 Crockford),因为它明确表明该变量在 for 循环之外可用:

function() {
    for(var i=0; i<7; i++) {
        // code
    }

    // i is still in scope here and has value 7
}
于 2012-04-18T00:20:55.527 回答
0

这两者是完全一样的。

于 2012-04-18T00:15:07.393 回答
0

这两个代码块是相同的。循环的第一条语句for在for循环开始之前执行,当第二条语句为真时循环正在运行,第三条语句在每次循环迭代一次时运行。

这意味着

for(var i = 0; i < 8; i++) {
    //some Code
}

等同于

var i = 0;
for(;i < 8;) {
    //some Code
    i++;
}

(后面的分号(是告诉计算机i < 8实际上是第二个语句,而不是第一个)。

于 2014-10-27T20:55:35.137 回答