9

在从 JS 编辑器 ( Tern )读取代码时,我遇到了 for 循环的各种用途,如下面的片段所示:

代码片段 1 @第 463-468 行

for (;;) {
  /* some code */
}

代码片段 2 @第 97-100 行

for (var i = 0; ; ++i) {
  /* some code */
}

同样,我还遇到了一个空主体的 for 循环,例如:

for (var p; p; p = someValue) /* empty body */ ;

我试图了解代码执行流程中发生了什么。

我的看法是,对于代码片段 1 中的代码,for 循环没有条件,所以它可能会无休止地继续吗?对于代码段 2 中的代码,i是否会无限制地不断递增?对于第三个,循环继续,直到p分配了一些评估为false?

这些是我心中的想法,但我不确定。请协助。

4

2 回答 2

5

简而言之

首先,您的所有断言都是正确的。

  • 第一个循环一直运行,直到它突然退出(使用中断、返回、抛出等)。
  • 第二个循环运行直到它突然退出,但也执行变量赋值,并增加一个值。
  • 第三个 for 循环像正常的 for 循环一样运行,直到中心条件为假。它的身体是空的。

但是为什么 JavaScript 会这样做呢?

让我们深入了解为什么会发生这种情况。

如果我们仔细查看语言规范,我们可以看到在 for 循环中发生了以下情况:

IterationStatement : for ( ExpressionNoIn(opt) ; Expression(opt) ; Expression(opt)) 语句

我将在其余答案中处理这些陈述和该定义。

现在让我们来看看这些案例。

如果for(;;)发生以下情况之一:

  • ExpressionNoIn 不存在,因此该子句不需要调用任何内容(如第 1 条所述)。

  • 第二个表达式不在,所以我们不返回调用(如第 3 条所述)。

  • 第三个表达式为空,因此不执行“增量”(如第 3.f 条所述)。

所以它基本上会像你预测的那样无休止地重复(直到用 a 打破break或返回,或抛出以及通常导致突然完成的任何事情)。(正如条款 e 和 d 告诉我们的那样)。

在第二种情况下for (var i = 0; ; ++i),会发生以下情况:

  • ExpressionNoIn 存在,因此我们对其进行评估,并为其分配 get 值(如第 1 条所述)。我们不分配它。

  • 然后我们无休止地重复,因为第二个表达式不在这里。所以我们继续直到发生突然执行或中断发生。更具体地说,这是在这里定义的。

  • 我们在每次迭代中递增i,如子句 f 所述。

在第三种情况下for (var p; p; p = someValue) /* empty body */ ;,会发生以下情况:

这评估为一个 for 循环。语句确实是空的,但 for 循环并不真正关心。唯一的区别是for 循环没有返回任何值。基本上它是一个完整且合法的 for 循环。;只是一个空语句。当您想在实际循环中运行没有内容的 for 循环时,它很有用。您有时会在特征检测中看到这一点。当您想找到最小值时,这也很有用n......

您是正确的,因为它会一直运行直到该值是错误的,或者更准确地调用ToBoolean它会产生 false. 正如第 3.a.ii 条规定的那样。

如您所见,这一切都在规范中并且定义明确:)


程序员为什么要这样做?

在第一个片段中,使用break子句执行他们的流控制。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<=10;i++);

并得到第一个大于 10 的数字。

于 2013-08-05T13:36:17.480 回答
1

你的理解是正确的。

第一个片段是一个无限循环;没有终止条件,因此循环将(本身)永远继续。这几乎可以肯定伴随着break主体内某处的语句,该语句将在运行时退出循环。(另一种选择是抛出的异常退出循环,尽管将异常用作控制流是不好的做法。)这种模式(或等效的while (true) {...})通常发生在退出条件太复杂而无法在循环语句中表达的情况下。

第二个片段类似于第一个片段,因为没有终止条件,它将永远运行。这也需要一个break语句(或异常)来终止循环。这里唯一的区别是计数器变量也在每次迭代中递增。

第三个片段是一个没有主体的循环,尽管测试和变量更新发生在循环的每次迭代中。如您所料,这将持续到p评估为false。这个 for 循环完全等同于 while 循环版本:

var p;
while (p) {
    p = someValue;
}

这可能更清楚地表明分配重复发生直到!p.

于 2013-08-05T13:37:59.380 回答