在从JS编辑器(Tern)中读取代码时,我遇到了for循环的各种用法,如下面的代码段所示:
代码段1 @ lines 463-468:
for (;;) {
/* some code */
}
代码段2 @ lines 97-100
for (var i = 0; ; ++i) {
/* some code */
}
在同一个音符上,我也遇到了一个带有空体的for循环,例如:
for (var p; p; p = someValue) /* empty body */ ;
我想了解代码执行流程中会发生什么。
我的看法是,对于代码片段1,for循环没有条件,所以它可能会无休止地继续?对于代码段2中的代码,i
会不断增加而不受限制?对于第三个循环,循环继续,直到为p
分配了一个评估为false
的东西?
这些是我脑子里的想法,但我不确定。请协助。
答案 0 :(得分:5)
首先,你的所有断言都是正确的。
让我们深入研究为什么会发生这种情况。
如果我们仔细看看the language specification,我们可以看到以下内容发生在for循环中:
IterationStatement:for(ExpressionNoIn(opt); Expression(opt); Expression(opt))Statement
我会将这些陈述和该定义视为答案的其余部分。
现在让我们来看看案例。
for(;;)
之一发生以下情况:ExpressionNoIn不存在,因此没有为该子句调用任何内容(As子句1指出)。
第二个表达式不在,所以我们不返回调用(如第3条所述)。
第三个表达式为空,因此不会执行“增量”(如第3.f条所述)。
所以它基本上会像你预测的那样无休止地重复(直到从break
中断,或从...返回,或从中抛出,并且通常是导致突然完成的任何东西)。 (正如条款e和d告诉我们的那样)。
for (var i = 0; ; ++i)
中,会发生以下情况:ExpressionNoIn存在,因此我们对其进行评估,并为其赋值get(如第1条所述)。我们不指定它。
然后我们无休止地重复,因为第二个表达不在这里。所以我们继续,直到abrubt执行发生或发生中断。更具体地说,这是here。
我们在每次迭代时递增i
,因为条款f表示。
for (var p; p; p = someValue) /* empty body */ ;
中发生以下情况:这评估为for循环。语句确实是空的,但for循环并不真正关心。唯一的区别是for循环中没有值返回。基本上它是一个完整且合法的循环。 ;
只是一个空话。当您想要在实际循环中运行没有内容的for循环时,它非常有用。你有时会在特征检测中看到这一点。当您想要找到......
n
时,这也很有用
你是正确的,因为它会运行,直到值为false,或更准确calling ToBoolean
on it produces false
。如第3.a.ii条规定。
正如您所看到的,这一切都在规范中并且定义明确:)
在第一个代码段中,使用a break
clause执行其流量控制。 if (eol >= pos || eol < 0) break;
(他们检查行尾,这可以在更传统的for循环中完成)。
在第二个片段中,他们使用break进行流量控制:
if (!definitions.hasOwnProperty(uniq)) { name = uniq; break; }
他们再次把它放在for循环中的break语句中。
第三个代码段不在上下文中,但是我们想要(通常的例子)找到大于10的第一个数字(或第10个div元素,或者是字符串的出现 - 你得到的)这个想法)。我们可以这样做:
for(var i = 0; i&lt; = 10; i ++);
获得第一个大于10的数字。
答案 1 :(得分:1)
你的理解是正确的。
第一个片段是无限循环;没有终止条件,所以循环(本身)将永远继续。这几乎肯定伴随着身体内某处的break
语句,它将在运行时退出循环。 (另一种选择是抛出异常退出循环,尽管使用异常作为控制流是不好的做法。)当退出条件过于复杂而无法表达时,通常会出现此模式(或等效的while (true) {...}
)循环语句。
第二个片段类似于第一个片段,因为没有终止条件,它将永远运行。这还需要break
语句(或异常)来终止循环。这里唯一的区别是计数器变量也在每次迭代时递增。
第三个片段是一个没有主体的循环,尽管测试和变量更新发生在循环的每次迭代中。如您所料,这一直持续到p
评估为false
。这个for循环完全等同于while循环版本:
var p;
while (p) {
p = someValue;
}
可能会更清楚地说明分配在!p
之前重复发生。