|
|
--- |
|
|
title: switch |
|
|
slug: Web/JavaScript/Reference/Statements/switch |
|
|
page-type: javascript-statement |
|
|
browser-compat: javascript.statements.switch |
|
|
sidebar: jssidebar |
|
|
--- |
|
|
|
|
|
The **`switch`** statement evaluates an [expression](/en-US/docs/Web/JavaScript/Guide/Expressions_and_operators), matching the expression's value against a series of `case` clauses, and executes [statements](/en-US/docs/Web/JavaScript/Reference/Statements) after the first `case` clause with a matching value, until a `break` statement is encountered. The `default` clause of a `switch` statement will be jumped to if no `case` matches the expression's value. |
|
|
|
|
|
{{InteractiveExample("JavaScript Demo: switch statement", "taller")}} |
|
|
|
|
|
```js interactive-example |
|
|
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}.`); |
|
|
} |
|
|
``` |
|
|
|
|
|
## Syntax |
|
|
|
|
|
```js-nolint |
|
|
switch (expression) { |
|
|
case caseExpression1: |
|
|
statements |
|
|
case caseExpression2: |
|
|
statements |
|
|
// … |
|
|
case caseExpressionN: |
|
|
statements |
|
|
default: |
|
|
statements |
|
|
} |
|
|
``` |
|
|
|
|
|
- `expression` |
|
|
- : An expression whose result is matched against each `case` clause. |
|
|
- `caseExpressionN` {{optional_inline}} |
|
|
- : A `case` clause used to match against `expression`. If the value of `expression` matches the value of any `caseExpressionN`, execution starts from the first statement after that `case` clause until either the end of the `switch` statement or the first encountered `break`. |
|
|
- `default` {{optional_inline}} |
|
|
- : A `default` clause; if provided, this clause is executed if the value of `expression` doesn't match any of the `case` clauses. A `switch` statement can only have one `default` clause. |
|
|
|
|
|
## Description |
|
|
|
|
|
A `switch` statement first evaluates its expression. It then looks for the first `case` clause whose expression evaluates to the same value as the result of the input expression (using the [strict equality](/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality) comparison) and transfers control to that clause, executing all statements following that clause. |
|
|
|
|
|
The clause expressions are only evaluated when necessary — if a match is already found, subsequent `case` clause expressions will not be evaluated, even when they will be visited by [fall-through](#breaking_and_fall-through). |
|
|
|
|
|
```js |
|
|
switch (undefined) { |
|
|
case console.log(1): |
|
|
case console.log(2): |
|
|
} |
|
|
// Only logs 1 |
|
|
``` |
|
|
|
|
|
If no matching `case` clause is found, the program looks for the optional `default` clause, and if found, transfers control to that clause, executing statements following that clause. If no `default` clause is found, the program continues execution at the statement following the end of `switch`. By convention, the `default` clause is the last clause, but it does not need to be so. A `switch` statement may only have one `default` clause; multiple `default` clauses will result in a {{jsxref("SyntaxError")}}. |
|
|
|
|
|
### Breaking and fall-through |
|
|
|
|
|
You can use the [`break`](/en-US/docs/Web/JavaScript/Reference/Statements/break) statement within a `switch` statement's body to break out early, often when all statements between two `case` clauses have been executed. Execution will continue at the first statement following `switch`. |
|
|
|
|
|
If `break` is omitted, execution will proceed to the next `case` clause, even to the `default` clause, regardless of whether the value of that clause's expression matches. This behavior is called "fall-through". |
|
|
|
|
|
```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 |
|
|
``` |
|
|
|
|
|
In the appropriate context, other control-flow statements also have the effect of breaking out of the `switch` statement. For example, if the `switch` statement is contained in a function, then a [`return`](/en-US/docs/Web/JavaScript/Reference/Statements/return) statement terminates the execution of the function body and therefore the `switch` statement. If the `switch` statement is contained in a loop, then a [`continue`](/en-US/docs/Web/JavaScript/Reference/Statements/continue) statement stops the `switch` statement and jumps to the next iteration of the loop. |
|
|
|
|
|
### Lexical scoping |
|
|
|
|
|
The `case` and `default` clauses are like [labels](/en-US/docs/Web/JavaScript/Reference/Statements/label): they indicate possible places that control flow may jump to. However, they don't create lexical [scopes](/en-US/docs/Glossary/Scope) themselves (neither do they automatically break out — as demonstrated above). For example: |
|
|
|
|
|
```js-nolint example-bad |
|
|
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."); |
|
|
} |
|
|
``` |
|
|
|
|
|
This example will output the error "Uncaught SyntaxError: Identifier 'message' has already been declared", because the first `const message = 'hello';` conflicts with the second `const message = 'hi';` declaration, even when they're within their own separate case clauses. Ultimately, this is due to both `const` declarations being within the same block scope created by the `switch` body. |
|
|
|
|
|
To fix this, whenever you need to use `let` or `const` declarations in a `case` clause, wrap it in a block. |
|
|
|
|
|
```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."); |
|
|
} |
|
|
} |
|
|
``` |
|
|
|
|
|
This code will now output `hello` in the console as it should, without any errors. |
|
|
|
|
|
## Examples |
|
|
|
|
|
### Using switch |
|
|
|
|
|
In the following example, if `expr` evaluates to `Bananas`, the program matches the value with case `case 'Bananas'` and executes the associated statement. When `break` is encountered, the program breaks out of `switch` and executes the statement following `switch`. If `break` were omitted, the statement for the `case 'Cherries'` would also be executed. |
|
|
|
|
|
```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?"); |
|
|
``` |
|
|
|
|
|
### Putting the default clause between two case clauses |
|
|
|
|
|
If no match is found, execution will start from the `default` clause, and execute all statements after that. |
|
|
|
|
|
```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"); |
|
|
} |
|
|
``` |
|
|
|
|
|
It also works when you put `default` before all other `case` clauses. |
|
|
|
|
|
### Taking advantage of fall-through |
|
|
|
|
|
This method takes advantage of the fact that if there is no `break` below a `case` clause, execution will continue to the next `case` clause regardless if that `case` meets the criteria. |
|
|
|
|
|
The following is an example of a single operation sequential `case` statement, where four different values perform exactly the same. |
|
|
|
|
|
```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."); |
|
|
} |
|
|
``` |
|
|
|
|
|
The following is an example of a multiple-operation sequential `case` clause, where, depending on the provided integer, you can receive different output. This shows you that it will traverse in the order that you put the `case` clauses, and it does not have to be numerically sequential. In JavaScript, you can even mix in definitions of strings into these `case` statements as well. |
|
|
|
|
|
```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!"); |
|
|
} |
|
|
``` |
|
|
|
|
|
The output from this example: |
|
|
|
|
|
| Value | Log text | |
|
|
| ----------------------------------------------------- | --------------------------------- | |
|
|
| `foo` is `NaN` or not `1`, `2`, `3`, `4`, `5`, or `0` | Please pick a number from 0 to 5! | |
|
|
| `0` | Output: So What Is Your Name? | |
|
|
| `1` | Output: What Is Your Name? | |
|
|
| `2` | Output: Your Name? | |
|
|
| `3` | Output: Name? | |
|
|
| `4` | Output: ? | |
|
|
| `5` | Output: ! | |
|
|
|
|
|
### An alternative to if...else chains |
|
|
|
|
|
You may often find yourself doing a series of [`if...else`](/en-US/docs/Web/JavaScript/Reference/Statements/if...else) matches. |
|
|
|
|
|
```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 |
|
|
} |
|
|
``` |
|
|
|
|
|
This pattern is not doing a sequence of `===` comparisons, but you can still convert it to a `switch` construct. |
|
|
|
|
|
```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; |
|
|
} |
|
|
``` |
|
|
|
|
|
The `switch (true)` pattern as an alternative to `if...else` is especially useful if you want to utilize the fall-through behavior. |
|
|
|
|
|
```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; |
|
|
} |
|
|
``` |
|
|
|
|
|
## Specifications |
|
|
|
|
|
{{Specifications}} |
|
|
|
|
|
## Browser compatibility |
|
|
|
|
|
{{Compat}} |
|
|
|
|
|
## See also |
|
|
|
|
|
- {{jsxref("Statements/if...else", "if...else")}} |
|
|
|