JavaScript 变量是在循环外还是在循环内声明?

IT技术 javascript performance
2021-02-03 16:08:38

在 AS3 中,我相信您应该初始化循环外的所有变量以提高性能。JavaScript 也是这种情况吗?哪个更好/更快/最佳实践?

var value = 0;

for (var i = 0; i < 100; i++)
{
    value = somearray[i];
}

或者

for (var i = 0 ; i < 100; i++)
{
    var value = somearray[i];
}
6个回答

绝对没有区别意义还是性能,在JavaScript或ActionScript。

var是解析器的指令,而不是在运行时执行的命令。如果var在函数体 (*) 的任何地方已经声明了一次或多次特定标识符,则块中对该标识符的所有使用都将引用局部变量。是否value声明var在循环内、循环外或两者都没有区别

因此,您应该编写任何您认为最易读的内容。我不同意 Crockford 的观点,即将所有变量放在函数顶部总是最好的。对于在一段代码中临时使用变量的情况,最好var在该段中声明,这样该段是独立的,可以复制粘贴。否则,在重构期间将几行代码复制粘贴到新函数中,而无需单独挑选和移动关联的var,您就会意外获得一个全局变量

特别是:

for (var i; i<100; i++)
    do something;

for (var i; i<100; i++)
    do something else;

Crockford 会建议您删除第二个var(或同时删除vars 和 dovar i;以上),并且 jslint 会为此向您发牢骚。但是 IMO 保留两个vars更易于维护,将所有相关代码保存在一起,而不是在函数顶部添加额外的、容易忘记的代码。

就我个人而言,我倾向于var在独立的代码部分中声明变量的第一次赋值,无论在同一函数的其他部分是否有另一个单独使用相同的变量名。对我来说,完全必须声明var是一个不受欢迎的 JS 疣(最好让变量默认为本地);我不认为我有责任在 JavaScript 中复制 [旧版本] ANSI C 的限制。

(*: 嵌套函数体除外)

我仍然无法决定我是否和 Crockford 在一起。在块内声明变量感觉有点像使用条件函数语句(这很调皮)......但是,我也同意你的观点:) #confused
2021-03-12 16:08:38
+1 Crockford 对这个(和其他人,但我离题了)是错误的。要求var仅在函数顶部使用只是要求意外创建全局变量。在一个地方声明大量不相关的变量在语义上是没有意义的,尤其是当其中一些变量最终可能永远不会被使用时。
2021-03-31 16:08:38
-1 OP 询问是否应在循环开始之前声明循环体中的变量。循环的索引值显然是一个特例(并且被提升)并且根本没有帮助 OP。
2021-04-01 16:08:38
+1 我不同意 Crockford 的推理(在 Daniel 的回答中引用),作为 JavaScript 开发人员,我们不应该编写代码以便其他“C 系列”程序员可以理解它。我经常if块和循环中使用var,因为它对我来说更有意义。
2021-04-04 16:08:38
循环索引不是特例,它们的处理和提升方式与正常赋值完全相同。
2021-04-06 16:08:38

理论上它在 JavaScript 中不应该有任何区别,因为该语言没有块作用域,而只有函数作用域。

我不确定性能参数,但Douglas Crockford仍然建议这些var语句应该是函数体中的第一条语句。引用JavaScript 编程语言的代码约定

JavaScript 没有块作用域,因此在块中定义变量可能会使熟悉其他 C 系列语言的程序员感到困惑。在函数顶部定义所有变量。

我认为他说的有道理,你可以在下面的例子中看到。在函数顶部声明变量不应该让读者误以为变量i 保存在for循环块的范围内

function myFunction() {
  var i;    // the scope of the variables is very clear

  for (i = 0; i < 10; i++) {
    // ...
  }
}
ES6 如何let影响这个答案?
2021-03-20 16:08:38
@Kieranmaine:AFAIK 即使您在循环内声明变量,ecma- / javascript也会在运行时将这些变量提升。这就是所谓的“吊装”。所以应该没有任何区别。
2021-03-22 16:08:38
@Kieranmaine:我没有说它不会影响性能。我只是提出了将它们放在循环之外的论点,与性能无关......我没有任何性能参数的参考,但你也没有在你的答案中引用任何内容:)
2021-04-03 16:08:38
@Kieranmaine:你有消息来源吗?
2021-04-07 16:08:38
+1 用于讲述有关 JS 范围的 OP 真相。我想知道是否要否决其他说法的答案!
2021-04-10 16:08:38

ECMA-/Javascript语言hoists被宣布为一个函数的顶部任何地方的任何变量。这是因为这种语言function scope和没有具有block scope像许多其他类似C语言。
这也称为lexical scope.

如果你声明类似的东西

var foo = function(){
    for(var i = 0; i < 10; i++){
    }
};

这得到hoisted

var foo = function(){
    var i;
    for(i = 0; i < 10; i++){
    }
}

所以它对性能没有任何影响(但如果我在这里完全错了,请纠正我)。不在函数顶部以外的其他地方声明变量的
一个更好的论据可读性在 a 中声明一个变量可能会导致错误的假设,即该变量只能在循环体内访问,这是完全错误的事实上,您可以在当前范围内的任何地方访问该变量。for-loop

ES6 如何let影响这个答案?
2021-04-01 16:08:38
与接受的答案相同的基本答案,但是,IMO,更具可读性,而且信息量也差不多。不错的工作。
2021-04-02 16:08:38

明年,所有浏览器都将拥有预编译代码的 JS 引擎,因此性能差异(来自一次又一次地解析相同的代码块加上执行赋值)应该可以忽略不计。

此外,除非必须,否则永远不要优化性能。将变量放在第一次需要它们的地方,可以保持代码整洁。不利的一面是,习惯于具有块作用域的语言的人可能会感到困惑。

另一个要考虑的,现在我们已经letconst在ES2015是,你现在可以作用域变量专门环形块。因此,除非您在循环外需要相同的变量(或者如果每次迭代都依赖于在前一次迭代中对该变量执行的操作),否则最好这样做:

for (let i = 0; i < 100; i++) {
    let value = somearray[i];
    //do something with `value`
}
我们不是在每次迭代中再次重新声明值吗?让如何允许?
2021-03-16 16:08:38
{之间的部分}是它自己的范围;let value特定于该块(我想也适用于该特定迭代)并且在下一次迭代中不再存在
2021-03-20 16:08:38