在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];
}
在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];
}
在 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会对此进行抱怨。但我个人认为保留两个var
更易于维护,将所有相关的代码放在一起,而不是在函数顶部有一个额外的容易被遗忘的代码块。var
,无论同一函数的其他部分是否有使用相同变量名的另外一个单独的用法。对我来说,在JS中声明var
本身就是一种不良的设计(最好让变量默认为局部变量);我不认为我的职责是复制JavaScript中[旧版] ANSI C的限制。var
仅在函数顶部使用只会导致意外创建全局变量。而将一堆不相关的变量都声明在一个地方,在语义上是没有意义的,尤其是其中一些变量可能永远都不会被使用。 - MooGoovar
语句应该是函数体中的第一条语句。引用Code Conventions for the JavaScript Programming Language的话来说:
我认为他说得有道理,正如您可以在以下示例中看到的那样。在函数顶部声明变量不应该让读者以为变量 在JavaScript没有块作用域,因此在块中定义变量可能会让有其他C系列语言经验的程序员感到困惑。请在函数顶部定义所有变量。
for
循环块的范围内:function myFunction() {
var i; // the scope of the variables is very clear
for (i = 0; i < 10; i++) {
// ...
}
}
for(var i; ...)
只会让初学者和最迷茫的JS程序员感到困惑,因为循环有其自己的作用域... - bryclet
关键字对这个答案有什么影响? - jbyrdECMA-/Javascript语言会将任何在函数内声明的变量进行提升(hoist)到函数顶部。这是由于该语言具有函数作用域(function scope)而不像其他类C语言一样具有块级作用域(block scope)。这也被称为词法作用域(lexical scope)。
如果你声明了如下代码:
var foo = function(){
for(var i = 0; i < 10; i++){
}
};
这个会被提升到:
var foo = function(){
var i;
for(i = 0; i < 10; i++){
}
}
因此,在性能方面没有任何区别(但如果我在这里完全错误,请纠正我)。
相比于在函数顶部之外的其他位置声明变量,更好的理由是 可读性。在 for-loop
中声明变量可能会导致错误的假设,即该变量只能在循环体内访问,这是完全错误的。实际上,您可以在当前范围内的任何地方访问该变量。
let
如何影响这个答案? - jbyrd明年,所有的浏览器都将拥有JS引擎来预编译代码,因此性能差异(来自于反复解析相同的代码块和执行赋值操作)应该会变得可以忽略不计。
此外,除非必须,否则不要为了性能而优化。让变量保持靠近第一次需要它们的地方可以使您的代码更加清晰。但是,不习惯块作用域语言的人可能会感到困惑。
另一个需要考虑的因素是,现在我们有了 ES2015 中的 let
和 const
,你可以将变量的作用域限定在循环块内。因此,除非你需要在循环外使用相同的变量(或者如果每次迭代都依赖于上一次迭代对该变量进行的操作),否则最好采用以下方法:
for (let i = 0; i < 100; i++) {
let value = somearray[i];
//do something with `value`
}
{}
之间的部分是它自己的作用域;let value
仅适用于该块(我想也适用于该特定迭代),并且在下一次迭代中不再存在。 - Matt Browne我刚在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());
var
声明了一个本来就是全局的变量。 - bobincefor (let i = 0, sum = 0; i < count; i++) { // count also be declared here like count = array.length;
sum = sum + 1;
}
根据之前提供的 测试 性能 fiddle,获胜者是第4个
这取决于你想要实现什么... 如果value
只是循环块内的临时变量,那么使用第二种形式会更清晰。它也更加合乎逻辑和详细。
在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
let
替换 var
,发现 a()
的速度稍慢一些(大约是 120 毫秒 vs 115 毫秒 = 约 6% = 在我看来不重要)。 - mikiqex