在AS3中,我认为你应该在循环之外初始化所有变量以提高性能。JavaScript也是这样吗?哪个更好/更快/最佳实践?

var value = 0;

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

or

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

理论上讲,这对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++) {
    // ...
  }
}

嗯,这取决于你想要达到什么目标……如果value只是循环块中的一个临时变量,那么使用第二种形式会更清楚。它也更有逻辑性和啰嗦。


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

此外,除非迫不得已,否则永远不要优化性能。将变量放在第一次需要它们的位置附近可以使代码干净。消极的一面是,习惯于使用块作用域的语言的人可能会感到困惑。


ECMA-/Javascript语言将任何声明在任何地方的变量提升到函数的顶部。这是因为该语言具有函数作用域,而不像许多其他类c语言那样具有块作用域。 这也被称为词汇范围。

如果你声明

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

这被提升为:

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

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


在JavaScript和ActionScript中,在意义和性能上没有任何区别。

Var是解析器的指令,而不是在运行时执行的命令。如果一个特定的标识符在函数体(*)中被声明为var一次或多次,那么该块中所有该标识符的使用都将引用该局部变量。value在循环内部、循环外部或两者都声明为var没有区别。

Consequently you should write whichever you find most readable. I disagree with Crockford that putting all the vars at the top of a function is always the best thing. For the case where a variable is used temporarily in a section of code, it's better to declare var in that section, so the section stands alone and can be copy-pasted. Otherwise, copy-paste a few lines of code to a new function during refactoring, without separately picking out and moving the associated var, and you've got yourself an accidental global.

特别是:

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

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

Crockford会建议你删除第二个变量(或者删除两个变量并执行var i;), jslint会因此抱怨你。但在我看来,保留两个变量更容易维护,将所有相关代码放在一起,而不是在函数顶部添加额外的、容易忘记的代码。

就我个人而言,我倾向于将变量的第一次赋值声明为var,无论在同一函数的其他部分是否有相同变量名的另一种单独用法。对我来说,必须声明var在所有是一个不受欢迎的JS疣(它会更好的变量默认为本地);我不认为在JavaScript中复制ANSI C(旧版本)的局限性是我的责任。

(*:除了嵌套函数体)


我只是在Chrome上做了一个简单的测试。在浏览器中尝试这一方法并查看结果

  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秒。非常重复,不考虑顺序。

所以,这向我证明了,应该总是在循环之外声明变量。对我来说,奇怪的情况是我在for()语句中声明I的第一个情况。这个测试似乎和第二个测试一样快,在第二个测试中,我预先声明了索引。


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


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

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

你认为这样对吗?不…因为你不想多次声明一个变量。当你在循环中声明一个变量时,它不是声明了循环运行的次数吗?显然,当你处于“严格使用”模式时,它会扇你耳光。人们不考虑最初的问题就不同意Crockford的观点。

所以在上面声明变量总是好的- 1。为了可读性,2。养成好习惯。


另一个需要考虑的问题是,既然我们在ES2015中有了let和const,现在你可以将变量的作用域专门用于循环块。因此,除非你在循环之外需要相同的变量(或者如果每次迭代都依赖于在前一次迭代中对该变量所做的操作),否则最好这样做:

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

关于在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;
}

注意变量'al'和'av'是如何在for循环声明行中出现的。这种内联声明一直为我提供了更好的性能。甚至在循环之外的变量声明。同样,性能差异非常小。

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


在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


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

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

根据之前提供的小提琴性能测试,获胜者是4号