JavaScript变量声明在循环外部或内部?

时间:2010-09-10 13:25:54

标签: javascript performance

在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];
}

12 个答案:

答案 0 :(得分:270)

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(或同时移除var并执行上面的var i;),jslint会为此向您发出警告。但IMO保持两个var,将所有相关代码保持在一起,而不是在函数顶部有一个额外的,容易被遗忘的代码,这样更容易维护。

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

(*:除嵌套函数体外)

答案 1 :(得分:65)

理论上它不应该对JavaScript产生任何影响,因为该语言没有块范围,只有函数范围。

我不确定性能参数,但Douglas Crockford仍然建议var语句应该是函数体中的第一个语句。引自Code Conventions for the JavaScript Programming Language

  

JavaScript没有块范围,因此在块中定义变量会使经验丰富的程序员与其他C族语言混淆。定义函数顶部的所有变量。

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

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

  for (i = 0; i < 10; i++) {
    // ...
  }
}

答案 2 :(得分:59)

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++){
    }
}

所以它在性能上没有任何差别(但如果我在这里完全错了,请纠正我) 在函数顶部而不是函数顶部声明变量的更好的理由是可读性。在for-loop内声明变量可能会导致错误的假设,即此变量只能在循环体中访问,这是完全错误。事实上,您可以在当前范围内的任何位置访问该变量。

答案 3 :(得分:13)

明年,所有浏览器都会有预编译代码的JS引擎,因此性能差异(一次又一次地解析相同的代码块以及执行分配)应该可以忽略不计。

此外,除非必须,否则永远不要优化性能。第一次将变量保持在您需要的位置附近可以保持代码清洁。从消极方面来说,习惯于使用块范围的语言的人可能会感到困惑。

答案 4 :(得分:4)

我刚刚在Chrome中做了一个简单的测试。在浏览器中试用fiddle并查看结果

  var count = 100000000;
    var a = 0;
    console.log(new Date());

    for (var i=0; i<count; i++) {
      a = a + 1
    }

    console.log(new Date());

    var j;
    for (j=0; j<count; j++) {
      a = a + 1;
    }

    console.log(new Date());

    var j;
    for (j=0; j<count; j++) {
        var x;
        x = x + 1;
    }

    console.log(new Date());

结果是最后一次测试需要约8秒,之前的2次测试仅需约2秒。非常重复,无论顺序如何。

所以,这向我证明,应该总是在循环之外声明变量。好奇的案例是我在for()语句中声明i的第一个案例。这个看起来和我预先声明索引的第二个测试一样快。

答案 5 :(得分:3)

现在我们在ES2015中有letconst的另一个考虑因素是,您现在可以将变量专门用于循环块。因此,除非你在循环外需要相同的变量(或者如果每次迭代都依赖于在前一次迭代中对该变量所做的操作),那么它可能更适合这样做:

for (let i = 0; i < 100; i++) {
    let value = somearray[i];
    //do something with `value`
}

答案 6 :(得分:1)

JavaScript是一种由C或C ++底层编写的语言,我不太确定它是哪一种。其目的之一是节省处理内存的重要性。 即使在C或C ++中,您也不必担心在循环内声明变量时是否会消耗大量资源。你为什么要在JavaScript中担心呢?

答案 7 :(得分:1)

我更喜欢将可读性和性能结合起来。 所以我最喜欢的是在循环内声明变量,这意味着我会有块作用域封装。

for (let i = 0, sum = 0; i < count; i++) { // count also be declared here like count = array.length;
  sum = sum + 1;
}

根据之前提供的小提琴演奏tests,获胜者是第 4 名

答案 8 :(得分:0)

那么,这取决于你想要实现的目标......如果value假设只是循环块内的临时变量,那么使用第二种形式就更清楚了。它也更符合逻辑和冗长。

答案 9 :(得分:0)

如果在for循环内部或外部声明变量,它就没有区别。 以下是要测试的示例代码。

function a() {
   console.log('Function a() starts');
   console.log(new Date());
    var j;
    for (j=0; j<100000000; j++) {
        var x;
        x = x + 1;
    }
    console.log(new Date());
    console.log('Function a() Ends');
}
a()
function b() {
console.log('Function B() starts');
   console.log(new Date());
    var a;
    var j;
    for (j=0; j<100000000; j++) {
      a = a + 1;
    }
    console.log(new Date());
    console.log('Function B() Ends');
}
b()

结果显示在我的案例中

Function a() starts
VM121:3 Thu Apr 12 2018 15:20:26 GMT+0530 (India Standard Time)
VM121:9 Thu Apr 12 2018 15:20:26 GMT+0530 (India Standard Time)
VM121:10 Function a() Ends
VM121:14 Function B() starts
VM121:15 Thu Apr 12 2018 15:20:26 GMT+0530 (India Standard Time)
VM121:21 Thu Apr 12 2018 15:20:26 GMT+0530 (India Standard Time)
VM121:22 Function B() Ends

谢谢 - MyFavs.in

答案 10 :(得分:-1)

这里的问题基本上是在循环中声明一个var。试想一下如果你这样做会发生什么:

var a = 30;
var a = 50;
var a = 60;

你认为这是对的吗?不...因为您不想多次声明变量。当你在循环中声明一个变量时,它不会声明循环运行多少次?当你处于'严格'模式时,它显然会打你。人们在不考虑原始问题的情况下不同意克罗克福德。

因此,最好将变量声明在上面 - 1.为了便于阅读,2。养成良好的习惯。

答案 11 :(得分:-2)

关于在Linux操作系统上运行Chrome,Firefox和jsperf测试后的性能,在循环中和循环中声明变量之间似乎存在性能差异。这是一个很小的差异,但迭代的数量和变量声明的数量也会加剧这一点。

因此,为了获得最佳性能,我必须建议在循环外声明变量。或者更好地声明你的变量。见例。

// inline
for (var ai = 0, al = 100000000, av; ai < al; ai++) {
    av = av + 1;
}

// outside
var bv;
var bl = 100000000;
for (var bi = 0; bi < bl; bi++) {
    bv = bv + 1;
}

注意变量&#39; al&#39;和&#39; av&#39;在for循环声明行中。这个内联声明为我提供了始终如一的更好的表现。甚至在循环之外的变量声明。性能差异再次非常小。

https://jsperf.com/outside-inline-for-loop-ase/1