while

while 语句创建一个循环,只要测试条件的计算结果为 true,该循环就会执行指定的语句。在执行语句之前评估条件。

¥The while statement creates a loop that executes a specified statement as long as the test condition evaluates to true. The condition is evaluated before executing the statement.

Try it

语法

¥Syntax

js
while (condition)
  statement
condition

在每次循环之前计算的表达式。如果这个条件 评估结果为真statement 被执行。当条件 评估结果为假 时,继续执行 while 循环之后的语句。

statement

只要条件计算结果为 true 就执行的可选语句。要在循环内执行多个语句,请使用 block 语句 ({ /* ... */ }) 对这些语句进行分组。

注意:使用 break 语句在 condition 计算结果为 true 之前停止循环。

示例

¥Examples

使用同时

¥Using while

只要 n 小于三,下面的 while 循环就会迭代。

¥The following while loop iterates as long as n is less than three.

js
let n = 0;
let x = 0;

while (n < 3) {
  n++;
  x += n;
}

每次迭代,循环都会递增 n 并将其添加到 x。因此,xn 取以下值:

¥Each iteration, the loop increments n and adds it to x. Therefore, x and n take on the following values:

  • 第一遍之后:n = 1 且 x = 1
  • 第二遍之后:n = 2 且 x = 3
  • 第三遍之后:n = 3 且 x = 6

完成第三遍后,条件 n < 3 不再成立,因此循环终止。

¥After completing the third pass, the condition n < 3 is no longer true, so the loop terminates.

使用赋值作为条件

¥Using an assignment as a condition

在某些情况下,使用赋值作为条件是有意义的。这伴随着可读性的权衡,因此有一些风格建议可以使该模式对每个人来说都更加明显。

¥In some cases, it can make sense to use an assignment as a condition. This comes with readability tradeoffs, so there are certain stylistic recommendations that would make the pattern more obvious for everyone.

考虑以下示例,该示例迭代文档的注释,并将它们记录到控制台。

¥Consider the following example, which iterates over a document's comments, logging them to the console.

js
const iterator = document.createNodeIterator(document, NodeFilter.SHOW_COMMENT);
let currentNode;
while (currentNode = iterator.nextNode()) {
  console.log(currentNode.textContent.trim());
}

这不完全是一个好的实践示例,具体是由于以下行:

¥That's not completely a good-practice example, due to the following line specifically:

js
while (currentNode = iterator.nextNode()) {

该行的效果很好 - 每次找到注释节点时:

¥The effect of that line is fine — in that, each time a comment node is found:

  1. iterator.nextNode() 返回该注释节点,该节点被分配给 currentNode
  2. 因此 currentNode = iterator.nextNode() 的值为 truthy
  3. 因此 console.log() 调用执行并且循环继续。

…然后,当文档中不再有注释节点时:

¥…and then, when there are no more comment nodes in the document:

  1. iterator.nextNode() 返回 null
  2. 因此,currentNode = iterator.nextNode() 的值也是 null,即 falsy
  3. 所以循环结束。

该行的问题是:条件通常使用 比较运算符,例如 ===,但该行中的 = 不是比较运算符 — 相反,它是 赋值运算符。因此,= 看起来像是 === 的拼写错误,尽管它实际上并不是拼写错误。

¥The problem with this line is: conditions typically use comparison operators such as ===, but the = in that line isn't a comparison operator — instead, it's an assignment operator. So that = looks like it's a typo for === — even though it's not actually a typo.

因此,在这种情况下,某些 代码检查工具(例如 ESLint 的 no-cond-assign 规则)(为了帮助你捕获可能的拼写错误以便你可以修复它)将报告如下警告:

¥Therefore, in cases like that one, some code-linting tools such as ESLint's no-cond-assign rule — in order to help you catch a possible typo so that you can fix it — will report a warning such as the following:

预期是一个条件表达式,但看到的是一个赋值。

¥Expected a conditional expression and instead saw an assignment.

许多样式指南建议更明确地表明条件作为赋值的意图。你可以通过在赋值周围添加额外的括号作为 分组运算符 来实现这一点:

¥Many style guides recommend more explicitly indicating the intention for the condition to be an assignment. You can do that minimally by putting additional parentheses as a grouping operator around the assignment:

js
const iterator = document.createNodeIterator(document, NodeFilter.SHOW_COMMENT);
let currentNode;
while ((currentNode = iterator.nextNode())) {
  console.log(currentNode.textContent.trim());
}

事实上,这是 ESLint 的 no-cond-assign 的默认配置以及 Prettier 强制执行的样式,因此你可能会在野外经常看到这种模式。

¥In fact, this is the style enforced by ESLint's no-cond-assign's default configuration, as well as Prettier, so you'll likely see this pattern a lot in the wild.

有些人可能会进一步建议添加比较运算符,将条件变成显式比较:

¥Some people may further recommend adding a comparison operator to turn the condition into an explicit comparison:

js
while ((currentNode = iterator.nextNode()) !== null) {

还有其他方法可以编写此模式,例如:

¥There are other ways to write this pattern, such as:

js
while ((currentNode = iterator.nextNode()) && currentNode) {

或者,完全放弃使用 while 循环的想法:

¥Or, forgoing the idea of using a while loop altogether:

js
const iterator = document.createNodeIterator(document, NodeFilter.SHOW_COMMENT);
for (
  let currentNode = iterator.nextNode();
  currentNode;
  currentNode = iterator.nextNode()
) {
  console.log(currentNode.textContent.trim());
}

如果读者足够熟悉作为条件模式的赋值,则所有这些变体都应该具有相同的可读性。否则,最后一种形式可能是最易读的,尽管是最冗长的。

¥If the reader is sufficiently familiar with the assignment as condition pattern, all these variations should have equivalent readability. Otherwise, the last form is probably the most readable, albeit the most verbose.

规范

Specification
ECMAScript Language Specification
# sec-while-statement

¥Specifications

浏览器兼容性

BCD tables only load in the browser

¥Browser compatibility

也可以看看