在循环中,结束条件中的任何操作都会在每次迭代中被评估吗?

7
在下面的代码中:
for (var i = 0; i < object.length; i++){  
    ....  
}  

object.length这个操作在迭代过程中会被重复执行吗?
通常情况下,语言会在第一次执行后保存结果,因此不需要每次都执行。然而,我读到一些代码,在循环开始之前计算了这个操作的值,并将其存储在一个变量中,在结束条件中使用了该变量。
不同的编程语言处理方式不同吗?有关JavaScript的特定信息吗?

8个回答

8

显然这取决于编程语言。对于JavaScript而言,在规范(ECMAScript §12.6.3)中要求每次都必须被执行。为了优化,如果特定的JavaScript运行时可以证明结果不会改变,它可以跳过一个或多个长度调用。


3
完全取决于语言和(可能)循环中的内容。编译器/解释器可能能够确定“length”属性是否会被循环中的某些内容更改,也可能无法确定。
在Javascript中,它很可能会被重新评估。像这样简单的属性引用可能不那么糟糕,但是像函数调用之类的东西可能会成为性能问题。编辑为了澄清,“函数调用”是指以任何形式计算循环终止条件的代码,如果每次迭代都让你感到不舒服,那就太昂贵了。
因此(请原谅我的jQuery),
for (var i = 0; i < $('.foo').length; ++i) { /* ... */ }

每次迭代都需要遍历整个DOM。


1
在动态语言中,函数调用本身并不直接与性能问题相关;例如,函数体可以被内联。 - C. K. Young
1
一个“简单属性引用”可以是调用复杂的getter函数(尽管在这种情况下应该是简单的)。 - Matthew Flaschen
@Chris - 哦,是的;我应该说的是“执行大量工作的函数调用”。我可以澄清一下。 - Pointy
另一个例子(使用 prompt 而不是 jQuery):for (var i=0; i<parseInt(prompt("最大 I?")); i++) { console.log("你好 "+i); } - Roy Tinker
你可以反向迭代 - 请参见下面的答案。 - Andrew Hodgkinson

2

必须在每次循环迭代时重新评估条件,因为理论上值可能已经在循环体内发生了变化。


2
一款智能编译器可以自动针对这种情况进行优化,但在JavaScript中进行静态分析以确定循环内的长度不会改变非常困难。因此,大多数情况下可以说object.length将在每次迭代中重新评估。
另一方面,对于程序员来说,推理出长度肯定不会改变通常更简单,如果你真的(我是说,真的)担心性能问题,你可以在循环开始前预先计算和存储长度。

2
如果您不在意顺序,可以反向迭代。在这种情况下,您不需要混乱的临时变量来保存长度。循环的起始条件仅被评估一次(显然,在循环已经开始后重新评估它是毫无意义的!)。使用早期回答中的示例:
for (var i = $('.foo').length - 1; i >= 0; i--) { /* ... */ }

我知道我回答这个问题已经很久了,但它仍然在Google搜索结果中显示高相关查询,并且现有的答案似乎都没有提出这种替代方法。


或者使用 for (var i = $('.foo').length; i --> 0;) { /* ... */ } 来获得额外的网络积分。 ;) - tne

1

0
在Javascript中,它每次都会被评估。您可以通过在循环的第一部分设置一个“max”变量来解决这个问题:
for (var i=0, imax=object.length; i<imax; i++) {
  // statements
}

0

是的,它在每次迭代中都会被计算。

为什么不测试一下呢?

var loop = 5;

for (var i = 0; i< loop; i++)
    {
    alert(i + ' of ' + loop);
    loop--;
    }

现场直播 http://jsfiddle.net/MSAdF/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接