The switch
statement evaluates an expression, matching the expression's value against a series of case
clauses, and executes 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.
Syntax
switch (expression) {
case value1:
statements
case value2:
statements
// …
case valueN:
statements
default:
statements
}
expression
- : An expression whose result is matched against each
case
clause.
- : An expression whose result is matched against each
case valueN
- : A
case
clause used to match againstexpression
. If theexpression
matches the specifiedvalueN
(which can be any expression), execution starts from the first statement after thatcase
clause until either the end of theswitch
statement or the first encounteredbreak
.
- : A
default
- : A
default
clause; if provided, this clause is executed if the value ofexpression
doesn't match any of thecase
clauses. Aswitch
statement can only have onedefault
clause.
- : A
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 comparison) and transfers control to that clause, executing all statements following that clause.
The clause values are only evaluated when necessary — if a match is already found, subsequent case
clause values will not be evaluated, even when they will be visited by fall-through.
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 SyntaxError.
Breaking and fall-through
You can use the 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 matches. This behavior is called "fall-through".
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
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
statement stops the switch
statement and jumps to the next iteration of the loop.
Lexical scoping
The case
and default
clauses are like labels: they indicate possible places that control flow may jump to. However, they don't create lexical scopes themselves (neither do they automatically break out — as demonstrated above). For example:
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.
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.
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.
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.
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.
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
matches.
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.
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.
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;
}