switch

Baseline 已广泛支持

此特性已相当成熟,可在许多设备和浏览器版本上使用。自 ⁨2015 年 7 月⁩以来,各浏览器均已提供此特性。

switch 语句对一个表达式进行求值,将其值与一系列 case 子句进行匹配,并执行第一个匹配的 case 子句之后的语句,直到遇到 break 语句。如果没有任何 case 与表达式的值匹配,则会跳转到 switch 语句的 default 子句。

试一试

const expr = "Papayas";
switch (expr) {
  case "Oranges":
    console.log("Oranges are $0.59 a pound.");
    break;
  case "Mangoes":
  case "Papayas":
    console.log("Mangoes and papayas are $2.79 a pound.");
    // Expected output: "Mangoes and papayas are $2.79 a pound."
    break;
  default:
    console.log(`Sorry, we are out of ${expr}.`);
}

语法

js
switch (expression) {
  case caseExpression1:
    statements
  case caseExpression2:
    statements
  // …
  case caseExpressionN:
    statements
  default:
    statements
}
表达式

一个表达式,其结果将与每个 case 子句进行匹配。

caseExpressionN 可选

用于与 expression 匹配的 case 子句。如果 expression 的值与任何 caseExpressionN 的值匹配,则执行从该 case 子句后的第一条语句开始,直到 switch 语句的末尾或遇到第一个 break 语句。

default 可选

一个 default 子句;如果提供了此子句,则当 expression 的值不匹配任何 case 子句时,将执行此子句。一个 switch 语句只能有一个 default 子句。

描述

一个 switch 语句首先对它的表达式求值。然后,它查找第一个其表达式求值结果与输入表达式结果值相同的 case 子句(使用严格相等比较),并将控制权转移到该子句,执行该子句之后的所有语句。

只有在必要时才会对子句表达式进行求值——如果已经找到匹配项,即使后续的 case 子句表达式会因穿透而被访问,也不会对其进行求值。

js
switch (undefined) {
  case console.log(1):
  case console.log(2):
}
// Only logs 1

如果没有找到匹配的 case 子句,程序会查找可选的 default 子句,如果找到,则将控制权转移到该子句,执行该子句之后的语句。如果没有找到 default 子句,程序将继续执行 switch 语句结束后的语句。按照惯例,default 子句是最后一个子句,但它不一定是最后一个。一个 switch 语句只能有一个 default 子句;多个 default 子句将导致 SyntaxError

中断和穿透

你可以在 switch 语句主体内使用 break 语句来提前跳出,通常是在两个 case 子句之间的所有语句都已执行完毕时。执行将继续在 switch 语句后的第一条语句。

如果省略 break,执行将继续到下一个 case 子句,甚至是 default 子句,无论该子句的表达式值是否匹配。这种行为称为“穿透”。

js
const foo = 0;
switch (foo) {
  case -1:
    console.log("negative 1");
    break;
  case 0: // Value of foo matches this criteria; execution starts from here
    console.log(0);
  // Forgotten break! Execution falls through
  case 1: // no break statement in 'case 0:' so this case will run as well
    console.log(1);
    break; // Break encountered; will not continue into 'case 2:'
  case 2:
    console.log(2);
    break;
  default:
    console.log("default");
}
// Logs 0 and 1

在适当的上下文中,其他控制流语句也具有跳出 switch 语句的效果。例如,如果 switch 语句包含在函数中,那么 return 语句会终止函数主体的执行,从而终止 switch 语句。如果 switch 语句包含在循环中,那么 continue 语句会停止 switch 语句并跳转到循环的下一次迭代。

词法作用域

casedefault 子句就像标签一样:它们指示控制流可能跳转到的位置。然而,它们本身并不创建词法作用域(它们也不会自动跳出——如上所示)。例如:

js
const action = "say_hello";
switch (action) {
  case "say_hello":
    const message = "hello";
    console.log(message);
    break;
  case "say_hi":
    const message = "hi";
    console.log(message);
    break;
  default:
    console.log("Empty action received.");
}

此示例将输出错误“Uncaught SyntaxError: Identifier 'message' has already been declared”,因为第一个 const message = 'hello'; 与第二个 const message = 'hi'; 声明冲突,即使它们位于各自独立的 case 子句中。最终,这是由于这两个 const 声明都位于由 switch 主体创建的同一块作用域内。

为了解决这个问题,每当你在 case 子句中需要使用 letconst 声明时,将其包装在一个块中。

js
const action = "say_hello";
switch (action) {
  case "say_hello": {
    const message = "hello";
    console.log(message);
    break;
  }
  case "say_hi": {
    const message = "hi";
    console.log(message);
    break;
  }
  default: {
    console.log("Empty action received.");
  }
}

这段代码现在将像预期一样在控制台中输出 hello,没有任何错误。

示例

使用 switch

在以下示例中,如果 expr 求值为 Bananas,程序将该值与 case 'Bananas' 匹配并执行关联的语句。当遇到 break 时,程序跳出 switch 并执行 switch 之后的语句。如果省略 break,则 case 'Cherries' 的语句也将被执行。

js
switch (expr) {
  case "Oranges":
    console.log("Oranges are $0.59 a pound.");
    break;
  case "Apples":
    console.log("Apples are $0.32 a pound.");
    break;
  case "Bananas":
    console.log("Bananas are $0.48 a pound.");
    break;
  case "Cherries":
    console.log("Cherries are $3.00 a pound.");
    break;
  case "Mangoes":
  case "Papayas":
    console.log("Mangoes and papayas are $2.79 a pound.");
    break;
  default:
    console.log(`Sorry, we are out of ${expr}.`);
}

console.log("Is there anything else you'd like?");

将 default 子句放在两个 case 子句之间

如果没有找到匹配项,执行将从 default 子句开始,并执行之后的所有语句。

js
const foo = 5;
switch (foo) {
  case 2:
    console.log(2);
    break; // it encounters this break so will not continue into 'default:'
  default:
    console.log("default");
  // fall-through
  case 1:
    console.log("1");
}

当你将 default 放在所有其他 case 子句之前时,它也适用。

利用穿透

此方法利用了这样一个事实:如果 case 子句下方没有 break,执行将继续到下一个 case 子句,无论该 case 是否符合条件。

以下是一个单操作顺序 case 语句的示例,其中四个不同的值执行完全相同的操作。

js
const Animal = "Giraffe";
switch (Animal) {
  case "Cow":
  case "Giraffe":
  case "Dog":
  case "Pig":
    console.log("This animal is not extinct.");
    break;
  case "Dinosaur":
  default:
    console.log("This animal is extinct.");
}

以下是多操作顺序 case 子句的示例,根据提供的整数,你可以收到不同的输出。这表明它将按照你放置 case 子句的顺序遍历,并且不必是数字顺序。在 JavaScript 中,你甚至可以在这些 case 语句中混合字符串定义。

js
const foo = 1;
let output = "Output: ";
switch (foo) {
  case 0:
    output += "So ";
  case 1:
    output += "What ";
    output += "Is ";
  case 2:
    output += "Your ";
  case 3:
    output += "Name";
  case 4:
    output += "?";
    console.log(output);
    break;
  case 5:
    output += "!";
    console.log(output);
    break;
  default:
    console.log("Please pick a number from 0 to 5!");
}

此示例的输出

日志文本
fooNaN 或不是 123450 请选择一个 0 到 5 之间的数字!
0 输出:你叫什么名字?
1 输出:你叫什么?
2 输出:名字?
3 输出:名?
4 输出:?
5 输出:!

if...else 链的替代方案

你可能经常发现自己进行一系列的 if...else 匹配。

js
if ("fetch" in globalThis) {
  // Fetch a resource with fetch
} else if ("XMLHttpRequest" in globalThis) {
  // Fetch a resource with XMLHttpRequest
} else {
  // Fetch a resource with some custom AJAX logic
}

此模式不是进行一系列的 === 比较,但你仍然可以将其转换为 switch 结构。

js
switch (true) {
  case "fetch" in globalThis:
    // Fetch a resource with fetch
    break;
  case "XMLHttpRequest" in globalThis:
    // Fetch a resource with XMLHttpRequest
    break;
  default:
    // Fetch a resource with some custom AJAX logic
    break;
}

switch (true) 模式作为 if...else 的替代方案,在你希望利用穿透行为时特别有用。

js
switch (true) {
  case isSquare(shape):
    console.log("This shape is a square.");
  // Fall-through, since a square is a rectangle as well!
  case isRectangle(shape):
    console.log("This shape is a rectangle.");
  case isQuadrilateral(shape):
    console.log("This shape is a quadrilateral.");
    break;
  case isCircle(shape):
    console.log("This shape is a circle.");
    break;
}

规范

规范
ECMAScript® 2026 语言规范
# sec-switch-statement

浏览器兼容性

另见