【问题标题】:Understanding JavaScript for-loop better更好地理解 JavaScript for 循环
【发布时间】:2013-08-05 13:27:47
【问题描述】:

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

代码 sn-p 1 @lines 463-468:

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

代码 sn-p 2 @lines 97-100

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

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

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

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

我的看法是,对于sn-p 1中的代码,for循环是没有条件的,所以它可能会无休止地继续下去?对于 sn-p 2 中的代码,i 会不断增加而没有限制?对于第三个,循环一直持续到 p 被赋值为 false?

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

【问题讨论】:

  • 你是对的。如果它们的主体中有break,则前两个循环可以完成。

标签: javascript for-loop


【解决方案1】:

简而言之

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

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

但为什么 JavaScript 会这样做呢?

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

如果我们仔细查看the language specification,我们可以看到在 for 循环中发生了以下情况:

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

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

现在让我们来看看案例。

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

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

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

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

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

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

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

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

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

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

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

您是正确的,因为它会一直运行直到值是假的,或者更准确地说是calling ToBoolean on it producesfalse。正如第 3.a.ii 条规定的那样。

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


程序员为什么要这样做?

在第一个 sn-p 中使用a break clause 执行流量控制。 if (eol >= pos || eol < 0) break;(他们检查行尾,这可以在更传统的 for 循环中完成)。

在第二个 sn-p 中,他们再次使用 break 进行流量控制:

 if (!definitions.hasOwnProperty(uniq)) { name = uniq; break; }

他们再次将它放在 for 循环内的 break 语句中。

第三个 sn-p 脱离上下文,但假设我们想要(简单的例子)找到第一个大于 10 的数字(或第 10 个 div 元素,或字符串的出现 -你明白了)。我们可以这样做:

for(var i=0;i

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

【讨论】:

  • 你为什么不用while (true)
  • @Nate 例如,当代码打高尔夫球时for(;;) 更短:P 老实说,没有充分的理由使用for(;;) 我解释了为什么它的行为方式而不是为什么有人会在代码中使用它。
【解决方案2】:

你的理解是正确的。

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

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

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

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

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

【讨论】:

    猜你喜欢
    • 2016-04-09
    • 1970-01-01
    • 1970-01-01
    • 2016-07-24
    • 1970-01-01
    • 2012-10-21
    • 1970-01-01
    • 1970-01-01
    • 2013-06-28
    相关资源
    最近更新 更多