循环和迭代

循环提供了一种快速、简单的方法来重复执行某些操作。JavaScript 指南 的这一章介绍了 JavaScript 可用的不同迭代语句。

¥Loops offer a quick and easy way to do something repeatedly. This chapter of the JavaScript Guide introduces the different iteration statements available to JavaScript.

你可以将循环视为游戏的计算机化版本,其中你告诉某人朝一个方向迈 X 步,然后朝另一个方向迈 Y 步。例如,想法 "向东走五步" 可以用循环的方式表示:

¥You can think of a loop as a computerized version of the game where you tell someone to take X steps in one direction, then Y steps in another. For example, the idea "Go five steps to the east" could be expressed this way as a loop:

js
for (let step = 0; step < 5; step++) {
  // Runs 5 times, with values of step 0 through 4.
  console.log("Walking east one step");
}

有许多不同类型的循环,但它们本质上都做同样的事情:他们多次重复某个动作。(请注意,该数字可能为零!)

¥There are many different kinds of loops, but they all essentially do the same thing: they repeat an action some number of times. (Note that it's possible that number could be zero!)

各种循环机制提供了不同的方法来确定循环的起点和终点。在许多情况下,一种类型的循环比其他类型的循环更容易满足。

¥The various loop mechanisms offer different ways to determine the start and end points of the loop. There are various situations that are more easily served by one type of loop over the others.

JavaScript 中提供的 for 循环语句是:

¥The statements for loops provided in JavaScript are:

对于声明

¥for statement

for 循环会重复,直到指定条件的计算结果为 false。JavaScript for 循环类似于 Java 和 C for 循环。

¥A for loop repeats until a specified condition evaluates to false. The JavaScript for loop is similar to the Java and C for loop.

for 语句如下所示:

¥A for statement looks as follows:

js
for (initialization; condition; afterthought)
  statement

当执行 for 循环时,会发生以下情况:

¥When a for loop executes, the following occurs:

  1. 执行初始化表达式 initialization(如果有)。该表达式通常会初始化一个或多个循环计数器,但语法允许使用任何复杂程度的表达式。该表达式还可以声明变量。
  2. 计算 condition 表达式。如果 condition 的值为 true,则执行循环语句。否则,for 循环终止。(如果完全省略 condition 表达式,则假定条件为 true。)
  3. statement 执行。要执行多个语句,请使用 块语句 ({ }) 对这些语句进行分组。
  4. 如果存在,则执行更新表达式 afterthought
  5. 控制返回到步骤 2。

示例

¥Example

在下面的示例中,该函数包含 for 语句,用于计算滚动列表中选定选项的数量(允许多项选择的 <select> 元素)。

¥In the example below, the function contains a for statement that counts the number of selected options in a scrolling list (a <select> element that allows multiple selections).

HTML

html
<form name="selectForm">
  <label for="musicTypes"
    >Choose some music types, then click the button below:</label
  >
  <select id="musicTypes" name="musicTypes" multiple>
    <option selected>R&B</option>
    <option>Jazz</option>
    <option>Blues</option>
    <option>New Age</option>
    <option>Classical</option>
    <option>Opera</option>
  </select>
  <button id="btn" type="button">How many are selected?</button>
</form>

JavaScript

这里,for 语句声明了变量 i 并将其初始化为 0。它检查 i 是否小于 <select> 元素中的选项数量,执行后续的 if 语句,并在每次循环后将 i 加 1。

¥Here, the for statement declares the variable i and initializes it to 0. It checks that i is less than the number of options in the <select> element, performs the succeeding if statement, and increments i by 1 after each pass through the loop.

js
function countSelected(selectObject) {
  let numberSelected = 0;
  for (let i = 0; i < selectObject.options.length; i++) {
    if (selectObject.options[i].selected) {
      numberSelected++;
    }
  }
  return numberSelected;
}

const btn = document.getElementById("btn");

btn.addEventListener("click", () => {
  const musicTypes = document.selectForm.musicTypes;
  console.log(`You have selected ${countSelected(musicTypes)} option(s).`);
});

do...while 语句

¥do...while statement

do...while 语句将重复执行,直到指定条件的计算结果为 false。

¥The do...while statement repeats until a specified condition evaluates to false.

do...while 语句如下所示:

¥A do...while statement looks as follows:

js
do
  statement
while (condition);

在检查条件之前,statement 始终执行一次。(要执行多个语句,请使用块语句 ({ }) 对这些语句进行分组。)

¥statement is always executed once before the condition is checked. (To execute multiple statements, use a block statement ({ }) to group those statements.)

如果 conditiontrue,则该语句再次执行。每次执行结束时,都会检查条件。当条件为 false 时,执行停止,控制权传递到 do...while 之后的语句。

¥If condition is true, the statement executes again. At the end of every execution, the condition is checked. When the condition is false, execution stops, and control passes to the statement following do...while.

示例

¥Example

在以下示例中,do 循环至少迭代一次并重复,直到 i 不再小于 5

¥In the following example, the do loop iterates at least once and reiterates until i is no longer less than 5.

js
let i = 0;
do {
  i += 1;
  console.log(i);
} while (i < 5);

while 语句

¥while statement

只要指定条件的计算结果为 truewhile 语句就会执行其语句。while 语句如下所示:

¥A while statement executes its statements as long as a specified condition evaluates to true. A while statement looks as follows:

js
while (condition)
  statement

如果 condition 变为 false,则循环内的 statement 将停止执行,并且控制权将传递到循环后面的语句。

¥If the condition becomes false, statement within the loop stops executing and control passes to the statement following the loop.

条件测试发生在循环中的 statement 执行之前。如果条件返回 true,则执行 statement 并再次测试 condition。如果条件返回 false,则执行停止,并且控制权将传递到 while 之后的语句。

¥The condition test occurs before statement in the loop is executed. If the condition returns true, statement is executed and the condition is tested again. If the condition returns false, execution stops, and control is passed to the statement following while.

要执行多个语句,请使用块语句 ({ }) 将这些语句分组。

¥To execute multiple statements, use a block statement ({ }) to group those statements.

实现例 1

¥Example 1

只要 n 小于 3,以下 while 循环就会迭代:

¥The following while loop iterates as long as n is less than 3:

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

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

¥With each iteration, the loop increments n and adds that value to x. Therefore, x and n take on the following values:

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

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

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

实现例 2

¥Example 2

避免无限循环。确保循环中的条件最终变为 false,否则循环将永远不会终止!以下 while 循环中的语句将永远执行,因为条件永远不会变为 false

¥Avoid infinite loops. Make sure the condition in a loop eventually becomes false—otherwise, the loop will never terminate! The statements in the following while loop execute forever because the condition never becomes false:

js
// Infinite loops are bad!
while (true) {
  console.log("Hello, world!");
}

标签声明

¥labeled statement

label 提供了一条带有标识符的语句,使你可以在程序的其他位置引用它。例如,你可以使用标签来标识循环,然后使用 breakcontinue 语句来指示程序是否应该中断循环或继续执行。

¥A label provides a statement with an identifier that lets you refer to it elsewhere in your program. For example, you can use a label to identify a loop, and then use the break or continue statements to indicate whether a program should interrupt the loop or continue its execution.

带标签语句的语法如下所示:

¥The syntax of the labeled statement looks like the following:

js
label:
  statement

label 的值可以是任何非保留字的 JavaScript 标识符。你通过标签识别的 statement 可以是任何声明。有关使用标记语句的示例,请参见下面的 breakcontinue 示例。

¥The value of label may be any JavaScript identifier that is not a reserved word. The statement that you identify with a label may be any statement. For examples of using labeled statements, see the examples of break and continue below.

中断语句

¥break statement

使用 break 语句终止循环,使用 switch 语句或与带标签的语句结合使用。

¥Use the break statement to terminate a loop, switch, or in conjunction with a labeled statement.

  • 当你使用不带标签的 break 时,它会立即终止最内层的 whiledo-whileforswitch,并将控制权转移到下面的语句。
  • 当你将 break 与标签一起使用时,它会终止指定的带标签语句。

break 语句的语法如下所示:

¥The syntax of the break statement looks like this:

js
break;
break label;
  1. 语法的第一种形式终止最内层的封闭循环或 switch
  2. 语法的第二种形式终止指定的封闭标记语句。

实现例 1

¥Example 1

以下示例迭代数组中的元素,直到找到值为 theValue 的元素的索引:

¥The following example iterates through the elements in an array until it finds the index of an element whose value is theValue:

js
for (let i = 0; i < a.length; i++) {
  if (a[i] === theValue) {
    break;
  }
}

示例 2:打破标签

¥Example 2: Breaking to a label

js
let x = 0;
let z = 0;
labelCancelLoops: while (true) {
  console.log("Outer loops:", x);
  x += 1;
  z = 1;
  while (true) {
    console.log("Inner loops:", z);
    z += 1;
    if (z === 10 && x === 10) {
      break labelCancelLoops;
    } else if (z === 10) {
      break;
    }
  }
}

继续声明

¥continue statement

continue 语句可用于重新启动 whiledo-whileforlabel 语句。

¥The continue statement can be used to restart a while, do-while, for, or label statement.

  • 当你使用不带标签的 continue 时,它会终止最内层封闭的 whiledo-whilefor 语句的当前迭代,并继续执行下一次迭代的循环。与 break 语句相反,continue 并不完全终止循环的执行。在 while 循环中,它跳回到条件。在 for 循环中,它跳转到 increment-expression
  • 当你将 continue 与标签一起使用时,它适用于用该标签标识的循环语句。

continue 语句的语法如下所示:

¥The syntax of the continue statement looks like the following:

js
continue;
continue label;

实现例 1

¥Example 1

以下示例显示了带有 continue 语句的 while 循环,该语句在 i 的值为 3 时执行。因此,n 采用值 13712

¥The following example shows a while loop with a continue statement that executes when the value of i is 3. Thus, n takes on the values 1, 3, 7, and 12.

js
let i = 0;
let n = 0;
while (i < 5) {
  i++;
  if (i === 3) {
    continue;
  }
  n += i;
  console.log(n);
}
// Logs:
// 1 3 7 12

如果注释掉 continue;,循环将运行到最后,你将看到 1,3,6,10,15

¥If you comment out the continue;, the loop would run till the end and you would see 1,3,6,10,15.

实现例 2

¥Example 2

标记为 checkiandj 的语句包含标记为 checkj 的语句。如果遇到 continue,则程序终止 checkj 的当前迭代并开始下一次迭代。每次遇到 continue 时,checkj 都会重复,直到其条件返回 false。当返回 false 时,checkiandj 语句的剩余部分完成,并且 checkiandj 重复执行,直到其条件返回 false。当返回 false 时,程序继续执行 checkiandj 后面的语句。

¥A statement labeled checkiandj contains a statement labeled checkj. If continue is encountered, the program terminates the current iteration of checkj and begins the next iteration. Each time continue is encountered, checkj reiterates until its condition returns false. When false is returned, the remainder of the checkiandj statement is completed, and checkiandj reiterates until its condition returns false. When false is returned, the program continues at the statement following checkiandj.

如果 continue 的标签为 checkiandj,则程序将从 checkiandj 语句的顶部继续执行。

¥If continue had a label of checkiandj, the program would continue at the top of the checkiandj statement.

js
let i = 0;
let j = 10;
checkiandj: while (i < 4) {
  console.log(i);
  i += 1;
  checkj: while (j > 4) {
    console.log(j);
    j -= 1;
    if (j % 2 === 0) {
      continue checkj;
    }
    console.log(j, "is odd.");
  }
  console.log("i =", i);
  console.log("j =", j);
}

for...in 声明

¥for...in statement

for...in 语句在对象的所有可枚举属性上迭代指定变量。对于每个不同的属性,JavaScript 都会执行指定的语句。for...in 语句如下所示:

¥The for...in statement iterates a specified variable over all the enumerable properties of an object. For each distinct property, JavaScript executes the specified statements. A for...in statement looks as follows:

js
for (variable in object)
  statement

示例

¥Example

以下函数将一个对象和该对象的名称作为其参数。然后,它迭代对象的所有属性并返回一个列出属性名称及其值的字符串。

¥The following function takes as its argument an object and the object's name. It then iterates over all the object's properties and returns a string that lists the property names and their values.

js
function dumpProps(obj, objName) {
  let result = "";
  for (const i in obj) {
    result += `${objName}.${i} = ${obj[i]}<br>`;
  }
  result += "<hr>";
  return result;
}

对于具有属性 makemodel 的对象 carresult 将是:

¥For an object car with properties make and model, result would be:

car.make = Ford
car.model = Mustang

数组

¥Arrays

尽管使用这种方式迭代 Array 元素可能很诱人,但 for...in 语句除了数字索引之外还将返回用户定义属性的名称。

¥Although it may be tempting to use this as a way to iterate over Array elements, the for...in statement will return the name of your user-defined properties in addition to the numeric indexes.

因此,在迭代数组时最好使用带有数字索引的传统 for 循环,因为如果修改 Array 对象(例如添加自定义属性或 方法)。

¥Therefore, it is better to use a traditional for loop with a numeric index when iterating over arrays, because the for...in statement iterates over user-defined properties in addition to the array elements, if you modify the Array object (such as adding custom properties or methods).

for...of 语句

¥for...of statement

for...of 语句创建一个循环迭代 可迭代对象(包括 ArrayMapSetarguments 对象等),调用自定义迭代钩子,其中包含针对每个不同属性的值执行的语句。

¥The for...of statement creates a loop Iterating over iterable objects (including Array, Map, Set, arguments object and so on), invoking a custom iteration hook with statements to be executed for the value of each distinct property.

js
for (variable of object)
  statement

以下示例显示了 for...of 循环和 for...in 循环之间的区别。for...in 迭代属性名称,而 for...of 迭代属性值:

¥The following example shows the difference between a for...of loop and a for...in loop. While for...in iterates over property names, for...of iterates over property values:

js
const arr = [3, 5, 7];
arr.foo = "hello";

for (const i in arr) {
  console.log(i);
}
// "0" "1" "2" "foo"

for (const i of arr) {
  console.log(i);
}
// Logs: 3 5 7

for...offor...in 语句也可以与 destructuring 一起使用。例如,你可以使用 Object.entries() 同时循环对象的键和值。

¥The for...of and for...in statements can also be used with destructuring. For example, you can simultaneously loop over the keys and values of an object using Object.entries().

js
const obj = { foo: 1, bar: 2 };

for (const [key, val] of Object.entries(obj)) {
  console.log(key, val);
}
// "foo" 1
// "bar" 2