switch
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}.`);
}
语法
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 子句表达式会因穿透而被访问,也不会对其进行求值。
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 子句,无论该子句的表达式值是否匹配。这种行为称为“穿透”。
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 语句并跳转到循环的下一次迭代。
词法作用域
case 和 default 子句就像标签一样:它们指示控制流可能跳转到的位置。然而,它们本身并不创建词法作用域(它们也不会自动跳出——如上所示)。例如:
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 子句中需要使用 let 或 const 声明时,将其包装在一个块中。
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' 的语句也将被执行。
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 子句开始,并执行之后的所有语句。
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 语句的示例,其中四个不同的值执行完全相同的操作。
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 语句中混合字符串定义。
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!");
}
此示例的输出
| 值 | 日志文本 |
|---|---|
foo 是 NaN 或不是 1、2、3、4、5 或 0 |
请选择一个 0 到 5 之间的数字! |
0 |
输出:你叫什么名字? |
1 |
输出:你叫什么? |
2 |
输出:名字? |
3 |
输出:名? |
4 |
输出:? |
5 |
输出:! |
if...else 链的替代方案
你可能经常发现自己进行一系列的 if...else 匹配。
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 结构。
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 的替代方案,在你希望利用穿透行为时特别有用。
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 |
浏览器兼容性
加载中…