人人都会AI编程

8.6 流程控制:分支、循环、跳转语句

更新时间:2026-07-11

流程控制决定了代码的执行顺序。默认情况下,JavaScript 从上到下逐行执行,但实际业务逻辑需要根据条件选择不同路径,或者重复执行某些操作。本节将逐一介绍分支语句、循环语句和跳转语句,它们是你控制代码流程的基础工具。

8.6.1 分支语句

分支语句让程序根据不同的条件执行不同的代码块。

if...else 语句

最基础的分支结构,有三种形态:

// 形态一:单分支
if (条件) {
    // 条件为 true 时执行
}

// 形态二:双分支
if (条件) {
    // 条件为 true 时执行
} else {
    // 条件为 false 时执行
}

// 形态三:多分支
if (条件1) {
    // 条件1为 true 时执行
} else if (条件2) {
    // 条件2为 true 时执行
} else {
    // 前面所有条件都为 false 时执行
}

实用要点:

  • 条件表达式会被隐式转换为布尔值,空字符串、0nullundefinedNaN 都视为 false
  • else if 并不是独立的语法结构,而是写在同一行避免深层嵌套的简写。等同于:
if (条件1) {
    // ...
} else {
    if (条件2) {
        // ...
    } else {
        // ...
    }
}
  • 只有一行代码时,花括号可以省略,但强烈不建议,容易引发歧义和错误。

switch 语句

当需要将一个值与多个可能情况匹配时,switch 比多层 if...else 更清晰:

const fruit = 'apple';

switch (fruit) {
    case 'apple':
        console.log('苹果');
        break;   // 跳出 switch,防止穿透
    case 'banana':
        console.log('香蕉');
        break;
    default:
        console.log('其他水果');
}

注意点:

  • 比较使用严格相等===),不会发生类型转换。
  • 穿透现象:如果没有 break,会继续执行下一个 case 的代码,直至遇到 breakswitch 结束。某些场景下可以利用穿透(比如多个情况执行相同逻辑),但必须谨慎,避免非预期的行为。
  • default 是可选的,当所有 case 都不匹配时执行。

8.6.2 循环语句

循环用于重复执行一段代码,直到满足停止条件。

for 循环

最经典的循环,适合事先知道循环次数或能用计数器控制的场景:

for (初始化; 条件; 更新) {
    // 循环体
}

// 示例:打印 0 到 4
for (let i = 0; i < 5; i++) {
    console.log(i);
}

三个表达式都可以省略,但分号不可省。例如死循环:for (;;)

while 循环

当条件为 true 时一直执行,适合不确定循环次数、只根据条件决定是否继续的情况:

while (条件) {
    // 循环体
}

let count = 0;
while (count < 5) {
    console.log(count);
    count++;
}

do...while 循环

先执行一次循环体,然后再判断条件。确保循环体至少执行一次

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

实际中使用频率不如 while 高,但在需要“先斩后奏”的场景(如用户输入验证,必须先展示提示框)时有用。

for...in 循环

用于遍历对象的可枚举属性(包括原型链上的属性):

const obj = { a: 1, b: 2, c: 3 };
for (let key in obj) {
    console.log(key, obj[key]);
}

重要提醒:

  • for...in 不适合遍历数组,因为它遍历的是索引(作为字符串),且会包含原型上扩展的属性,可能导致意外的结果。
  • 如果只想获取对象自身的属性,需要在循环内用 hasOwnProperty 过滤:
for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
        // 处理自身属性
    }
}

for...of 循环

ES6 引入的迭代器循环,遍历可迭代对象(如数组、字符串、Map、Set)的值:

const arr = [10, 20, 30];
for (let value of arr) {
    console.log(value);   // 10, 20, 30
}

const str = 'hello';
for (let char of str) {
    console.log(char);    // h, e, l, l, o
}

与 for...in 对比:

| 特性 | for...in | for...of |
|------|----------|----------|
| 设计用途 | 遍历对象键名 | 遍历可迭代对象的值 |
| 遍历数组时得到 | 索引(字符串) | 元素值 |
| 支持自定义迭代器 | 否 | 是 |
| 包含原型属性 | 是(需要过滤) | 不会 |

实用场景: 遍历数组优先用 for...offorEach,遍历对象用 Object.keys() / Object.values() 配合普通循环,避免 for...in 的坑。

8.6.3 跳转语句

跳转语句用于改变循环或函数的正常执行流。

break

立即终止当前循环,不再执行后续迭代,常用于提前退出:

for (let i = 0; i < 10; i++) {
    if (i === 5) break;
    console.log(i);   // 输出 0 到 4
}

在嵌套循环中,break 只退出最内层循环。如果想要跳出外层循环,可以使用标签(见下文)。

continue

跳过当前迭代的剩余代码,直接进入下一次循环的条件判断:

for (let i = 0; i < 5; i++) {
    if (i === 2) continue;
    console.log(i);   // 输出 0, 1, 3, 4,跳过了 2
}

return

用于函数体内,终止函数执行并返回一个值(可省略,返回 undefined)。当 return 出现在循环中时,不仅终止循环,还直接结束整个函数:

function findFirstEven(arr) {
    for (let num of arr) {
        if (num % 2 === 0) return num;
    }
    return null;   // 没找到则返回 null
}

标签语句

JavaScript 允许给语句加标签,配合 breakcontinue 跳转到指定的外层循环或代码块:

outerLoop: for (let i = 0; i < 3; i++) {
    for (let j = 0; j < 3; j++) {
        if (i === 1 && j === 1) break outerLoop;  // 跳出外层循环
        console.log(i, j);
    }
}
// 输出: 0 0, 0 1, 0 2, 1 0,然后跳出

标签在实际工作中不常用,但在处理多重循环且需要一次性跳出的场景下非常有效,相比设置多个标志变量更简洁。

8.6.4 实用建议

  1. 优先使用可读性高的写法

for...of 配合迭代器让循环意图更清晰;能用 forEach 表达的就不要自己写 for 循环,除非需要提前退出。

  1. 避免死循环

确保循环的终止条件最终能达到,尤其在 whiledo...while 中。开发时可加入最大迭代次数计数器,防止浏览器页面卡死。

  1. switch 不要漏掉 break

大部分情况下每个 case 后都要跟 break,即使放在 default 后也可以习惯性加一个(虽然不需要)。

  1. 注意数组遍历的坑
  • for...in 遍历数组会得到字符串索引且可能包含原型属性,不要用。
  • for...of 遍历数组得到的是值,无法直接获取索引,如需索引可用 arr.entries()
  • 稀疏数组的遍历行为有差异,forEachfor...of 会跳过空元素,而普通 for 循环会访问 undefined

掌握了这些流程控制语句,你就能够编写出灵活且健壮的程序逻辑。它们是构建更复杂算法和业务逻辑的基础积木。