The switch statement
Choose between many JavaScript cases with strict matching, break, default, intentional fallthrough, and object lookup alternatives.
- 01Match cases exactlyExplain why the text "1" does not match
case 1: a switch compares like ===. - 02Stop the code at the right placeUse break, return, default, and shared cases, and say what runs when break is missing.
- 03Pick the clearest way to chooseDecide when to use a switch, an if / else chain, or an object lookup.
Choose one path from many exact values
INTERACTIVEThe switch statement is a way to make a choice in your code. It fits one kind of choice well: you have one value, and you want different code for each exact value it might have.
You can do the same job with if and else if. A switch is easier to read when your question is "Which exact value is this?"
Two things from earlier lessons matter here:
- In Comparisons, you saw that
===checks the value and the type. Aswitchcompares the same way. - In Type conversion, you saw that input from a user usually arrives as text (a string).
Put together, this means the text "1" does not match a case for the number 1. You'll see why in the next section.
You type B3 into a vending machine. The machine does not try A1, then A2, then A3. It goes straight to slot B3.
- In real life: You type B3
- In JavaScript:
switch (slot)reads one value - In real life: The machine goes to slot B3
- In JavaScript: JavaScript goes to the
casewith that value - In real life: A code with no slot needs a backup plan
- In JavaScript:
defaultruns when no case matches - In real life: The snack drops, and you are done
- In JavaScript:
breakorreturnends that case
Here is the shape of every switch in this lesson:
switch (value) { case "first": // statements for first break; case "second": // statements for second break; default: // statements when no case matched}The parts, line by line:
switch (value)on line 1 names the value to check.- Each
case, likecase "first":on line 2, is a case label: one value the switch might match. breakon line 4 ends the switch.defaulton line 8 is the code to run when no case matches.
The rule to remember: JavaScript finds the first case that matches. It starts running there. Then it keeps running the lines below, until something stops it. Most of this lesson is about two questions: what counts as a match, and what stops the code.
const drink = "tea";let message; switch (drink) { case "tea": message = "Tea is ready"; break; default: message = "Choose another drink";} console.log(message);Line by line:
- Line 1 stores
"tea"indrink. - Line 4 starts the switch on
drink. - Line 5 matches, because the value is
"tea". Line 6 setsmessagetoTea is ready. - Line 7,
break, ends the switch. - Line 12 prints
Tea is ready.
If drink were "coffee", no case would match. Then default would run, and the code would print Choose another drink.
drink once. Then it goes to the case with that exact value, case "tea", and starts there. default is skipped, because a case matched.A case must match exactly
TRY ITA switch compares its value with each case label using strict matching. That is the same check as ===: the value must be the same, and the type must be the same. JavaScript does not turn text into a number to make a case match.
const input = "1";let label; switch (input) { case 1: label = "number one"; break; case "1": label = "string one"; break; default: label = "unknown";} console.log(label);This prints string one. Line 1 stores the text "1". Line 5 is a case for the number 1. Text and a number are different types, so line 5 does not match. Line 8 is a case for the text "1". Same type, same value, so it matches.
"1". The number 1 looks the same, but it is a different type, so case 1 does not match. Only case "1" matches.const seats = 2; switch (seats) { case 1 + 1: console.log("two seats"); break; default: console.log("another number");}A case label does not have to be a value you type out. It can be an expression: a piece of code that produces a value. On line 4, 1 + 1 produces 2. That matches seats, so line 5 prints two seats. Still, keep case labels simple, as the next example shows.
const code = "B"; function label(value) { console.log("check", value); return value;} switch (code) { case label("A"): break; case label("B"): console.log("matched B");}The function label prints a message each time it runs, so you can see when JavaScript checks a case. This code prints three lines:
check A: line 9 runslabel("A")."A"is not"B", so there is no match.check B: line 11 runslabel("B"). That matches.matched B: line 12 runs.
JavaScript checks case labels in order, and it stops checking at the first match. So a case label that does real work, like loading data, may run or may not. That is why case labels should stay simple.
const score = Number("not a number"); switch (score) { case NaN: console.log("a number"); break; default: console.log("not a number");}NaN means "not a number". You get it when a number can't be made, like on line 1. NaN is the one value that is not equal to itself: NaN === NaN is false. So case NaN on line 4 never matches, and line 8 prints not a number.
To catch NaN, check Number.isNaN(score) before the switch. It gives true when score is NaN.
Now step through the same input two ways. First keep it as text. Then turn it into a number with Number(input) before the switch. Watch which case matches each time.
Switch between text and a number, then step through again. Only the case with the same type matches.
script
const value = input;let label = ""; switch (value) { case 1: label = "number one"; break; case "1": label = "string one"; break; default: label = "unknown";} console.log(label);const input = "1";const value = Number(input); // or keep input as a string switch (value) { case 1: console.log("number one"); break; case "1": console.log("string one"); break; default: console.log("unknown");}"1"stringThe switch value is "1", a string. The matching case sets label to "string one".
A form field, a prompt() box, or a web address gives you text. Pick one type for your cases, then make the value match it:
- If your cases are numbers, turn the input into a number once, with
Number(input). - If the codes are meant to be text, write text cases, like
case "1":.
You may also see switch (true) used for ranges of numbers:
const score = 82;let grade; switch (true) { case score >= 90: grade = "A"; break; case score >= 80: grade = "B"; break; default: grade = "keep practicing";} console.log(grade);Here the switch value is true. Each case label is a check, like score >= 90, that gives true or false. The first check that gives true matches. With a score of 82, line 5 gives false and line 8 gives true, so the grade is B.
This works, but use it rarely. For ranges, an if / else if chain is usually easier to read, because each line plainly shows its check.
break, and what happens without it
STEP THROUGHA switch does not stop by itself at the next case label. After a match, JavaScript runs every line below it, even the lines under other case labels. A break statement ends the switch.
When the code runs on into the next case, that is called fallthrough: the code "falls through" to the case below.
Picture a staircase in the rain. Water lands on one step. Then it flows down to the next step, and the next, until a wall stops it.
- In real life: Rain lands on one step
- In JavaScript: The code starts at the matching case
- In real life: The water flows to the lower steps
- In JavaScript: The lines below run too
- In real life: A wall stops the water
- In JavaScript:
breakends the switch - In real life: With no wall, the next step gets wet
- In JavaScript: With no
break, the next case runs
case "yellow". On the left, break ends the switch, so the action stays "slow down". On the right there is no break, so the green case runs too and changes the action to "go".Try it in the step-through below. Pick yellow, then remove the break from the yellow case. The result changes from slow down to go, because the green case runs after the yellow case.
Pick a color, then step through the switch. Try yellow with and without its break, and compare the results.
script
let action = ""; switch (color) { case "red": action = "stop"; break; case "yellow": action = "slow down"; break; case "green": action = "go"; break; default: action = "check the signal";} console.log(action);Some cases have no lines of their own and share the code below them. That is common and safe; you'll see it in a later section.
Sometimes you want a case to run its own lines and then fall into the next case. Then add the comment // falls through where the break would go. ESLint, the code checker from the Linting lesson, has a rule called no-fallthrough. It warns about a missing break, but it stays quiet when it sees that comment.
default runs when no case matches
EDGE CASESThe default label runs when no case matches. It is like a "none of these" choice. Most code puts it last, because that is easiest to read. But JavaScript lets you put it anywhere in the switch.
const drink = "juice"; switch (drink) { case "tea": console.log("Tea is ready"); break; case "coffee": console.log("Coffee is ready"); break; default: console.log("Not on the menu");}"juice" matches neither "tea" nor "coffee". So only default runs, and line 11 prints Not on the menu.
This default needs no break, because it is last. After its lines, the switch simply ends. If other cases came after it, it would need a break.
const size = "large";let price; switch (size) { default: price = "ask staff"; break; case "small": price = 3; break; case "large": price = 5;} console.log(price);Here size is "large". JavaScript skips the default on line 5, because it still checks every case first. case "large" on line 11 matches, so line 12 sets price to 5, and the code prints 5. Being first did not make default run first.
But default follows the same break rule as every case:
const size = "medium";let price = ""; switch (size) { default: price = "unknown"; case "large": price = price + " size";} console.log(price);Line by line:
"medium"matches no case, sodefaulton line 5 runs.- Line 6 sets
priceto"unknown". - There is no
break, so the code falls through tocase "large". - Line 8 adds
" size"to the end ofprice.
The code prints unknown size.
Common ways to use a switch
PATTERNSThe safest fallthrough is a case with no lines of its own, sitting right above another case. Both cases then share one set of lines. Weekend days are a good example:
const day = "Saturday";let kind; switch (day) { case "Saturday": case "Sunday": kind = "weekend"; break; default: kind = "weekday";} console.log(kind);case "Saturday" on line 5 has no lines of its own. So the code falls through to case "Sunday" and runs line 7, which sets kind to "weekend". This fallthrough is on purpose, and it is easy to read. The shared lines still end with break on line 8.
A switch inside a function often uses return in each case. return ends the whole function and hands back a value. So it also stops the code from falling into the next case.
function shipping(speed) { switch (speed) { case "overnight": return 25; case "standard": return 7; default: return 0; }} console.log(shipping("standard"));shipping("standard") matches case "standard". Line 6, return 7, ends the function, and the code prints 7. A break after a return would never run, so you don't write one.
You'll use a switch for short lists of exact values, such as:
- keyboard commands, like
"copy"or"paste" - status words, like
"loading"or"done" - page names, display modes, and other fixed labels
If the list grows long, or if it comes from data, the next section shows a shorter way.
Use an object as a lookup table
SORTERSometimes every case of a switch just gives back a value: "apple means 1.2, banana means 0.5". For that job, an object is often shorter and safer than a switch.
const prices = { apple: 1.2, banana: 0.5, cherry: 2,}; const fruit = "banana";const price = prices[fruit] ?? "unknown";console.log(price);Line by line:
- Lines 1 to 5 make an object called
prices. Each line inside the braces pairs a name, called a key, with a value:applewith1.2, and so on. - Line 7 stores the key to look for,
"banana", infruit. - On line 8,
prices[fruit]finds the value for that key:0.5. The square brackets look up the key held infruit. - If the key is missing,
prices[fruit]givesundefined. Then??gives the backup value"unknown". (??means "use the right side if the left side isnullorundefined".) - Line 9 prints
0.5.
prices is a small table of names and prices. prices[fruit] takes the name in fruit, finds it in the table, and gives back its price, 0.5. No cases, no break.Objects get a full lesson in Stage 3. For now, read the braces as a small table. A related tool, Map, comes later in the Map & Set lesson.
const prices = { apple: 1.2, banana: 0.5,};const fruit = "toString"; const price = Object.hasOwn(prices, fruit) ? prices[fruit] : "unknown";console.log(price);Every plain object also has some built-in names that you did not write, such as toString. So if a user types toString, prices[fruit] finds something, even though it is not a fruit.
Object.hasOwn(prices, fruit) on line 7 fixes this. It gives true only when you wrote that key in the table yourself. Here it gives false, so line 9 picks "unknown", and the code prints unknown. Use this check when the key comes from a form, a web address, or a server.
const prices = { apple: 1.2, banana: 0.5, cherry: 2,}; const fruit = "banana";const price = prices[fruit] ?? "unknown";console.log(price);bananaFor banana, the switch returns 0.5 and the lookup returns 0.5.
The table below compares three ways to choose. Read each row as a question, then compare the three answers.
| Question | switch | if / else | Object lookup |
|---|---|---|---|
| What question does it answer? | Which exact value is this? | Which check is true? | What value goes with this key? |
| What does the input look like? | One text or number with a few known values. | Ranges, several variables, or yes-or-no checks. | A text key, like a product name. |
| What often goes wrong? | You forget break, and the next case runs too. | You put the checks in the wrong order. | A missing key gives undefined. |
| Can the choices come from data? | Not easily. Every case is written in the code. | Not easily. A long chain gets hard to read. | Yes. Code can build or change the object. |
| When should a beginner use it? | For a short list of exact values. | When each choice asks a different question. | When each key goes with one value. |
- A command is exactly
copy,paste,cut, orundo. - Say whether the temperature is below 0, below 20, or higher.
- Each fruit name goes with a price, and the prices come from data.
- Saturday and Sunday should run the same code.
- Each role name goes with a small function to run.
- Check for an empty name, then a wrong email, then a short password, in that order.
Put each task under the way that reads most clearly. Other ways may also work, but pick the one a beginner would find easiest to read and change.
Common mistakes
"A switch turns text into numbers when it compares."
It does not. case 1 will not match "1". Turn the value into a number first, or write text cases.
"Only the matching case runs."
The matching case is where the code starts. The lines below it run too, until a break, a return, or the end of the switch.
"default must be last."
It can go anywhere. Last is usually easiest to read. Wherever it is, it can still fall through without a break.
"Fallthrough is always a bug."
A missing break is often a bug. But grouped cases, like Saturday and Sunday, share code on purpose. If a case runs its own lines and then falls through on purpose, add a comment that says so.
"Each case has its own block."
A block is code inside curly braces. Variables made with let or const belong to their block. All cases share the one block of the switch. So two let variables with the same name, in two cases, clash. The error happens before any code runs.
switch ("a") { case "a": let message = "alpha"; break; case "b": let message = "bravo"; break;}Lines 3 and 6 both make a variable called message in the same block. JavaScript stops with a SyntaxError: a mistake in how the code is written, found before it runs.
switch ("a") { case "a": { let message = "alpha"; console.log(message); break; } case "b": { let message = "bravo"; console.log(message); break; }}The { on lines 2 and 7 starts a new block for each case. Now each message lives in its own block, so they don't clash. The code prints alpha.
If a case makes a variable with let or const, put that case's lines in braces. Then you can see where the variable belongs, and a later variable with the same name won't clash.
Practice: follow and rewrite switches
5 EXERCISESFor the "what does it print?" exercises, don't run the code first. Find the matching case. Then read down until something stops the code. After you answer, paste the code into your console to check.
What exact text does this code print?
let badge = "";
switch ("silver") {
case "gold":
badge = "Gold";
break;
case "silver":
badge = "Silver";
case "bronze":
badge = badge + " + Bronze";
break;
default:
badge = "No badge";
}
console.log(badge);The silver case sets badge to Silver. There is no break, so the bronze case runs next and adds + Bronze. The code prints Silver + Bronze.
"1" and 1 mix-upFirst, predict what this code prints. Then change it so it finds the first page.
const input = "1";
let page;
switch (input) {
case 1:
page = "first";
break;
default:
page = "not found";
}
console.log(page);const input = "1";
let page;
switch (Number(input)) {
case 1:
page = "first";
break;
default:
page = "not found";
}
console.log(page);The first version prints not found, because the text "1" does not match the number 1. Number(input) turns the text into a number, so case 1 matches and the code prints first.
Write a switch, or explain this one, where Saturday and Sunday both give weekend.
const day = "Saturday";
let kind;
switch (day) {
case "Saturday":
case "Sunday":
kind = "weekend";
break;
default:
kind = "weekday";
}
console.log(kind);const day = "Saturday";
let kind;
switch (day) {
case "Saturday":
case "Sunday":
kind = "weekend";
break;
default:
kind = "weekday";
}
console.log(kind);case "Saturday" has no lines of its own, so it falls through to Sunday's lines on purpose. Both days set kind to weekend. Then break ends the switch.
Rewrite the function so it gives the same results without a switch. It should still return ❓ for a status it doesn't know.
function emojiForStatus(status) {
switch (status) {
case "success":
return "✅";
case "warning":
return "⚠️";
case "error":
return "🚨";
default:
return "❓";
}
}
console.log(emojiForStatus("warning"));function emojiForStatus(status) {
const icons = {
success: "✅",
warning: "⚠️",
error: "🚨",
};
return icons[status] ?? "❓";
}
console.log(emojiForStatus("warning"));The object is a small table from status words to icons. icons[status] finds the icon for the status. ?? gives the same backup icon as default. For warning, both versions print ⚠️.
Add a backup so that a drink size code the switch doesn't know returns unknown size.
function drinkSize(code) {
switch (code) {
case "S":
return "small";
case "M":
return "medium";
}
}
console.log(drinkSize("XL"));function drinkSize(code) {
switch (code) {
case "S":
return "small";
case "M":
return "medium";
default:
return "unknown size";
}
}
console.log(drinkSize("XL"));default catches every code that is not S or M. Now drinkSize("XL") returns unknown size instead of undefined.
Quiz: check your understanding
7 QUESTIONSRead each code sample carefully. After you pick an answer, read the explanation under it. That is where the learning happens.
Question 1 of 7How does
switchcompare its value with eachcase?Choose an answer to see the explanation.
Question 2 of 7What does this code print?
Read the code, then predictconst value = "1"; switch (value) { case 1: console.log("number"); break; case "1": console.log("string"); break; default: console.log("other"); }Choose an answer to see the explanation.
Question 3 of 7Case A has no
break. What does this code print?Read the code, then predictlet result = ""; switch ("A") { case "A": result += "Alpha"; case "B": result += "Beta"; break; } console.log(result);Choose an answer to see the explanation.
Question 4 of 7What is the clearest way to run the same code for
SaturdayandSunday?Choose an answer to see the explanation.
Question 5 of 7
defaulthas nobreak. What does this code print?Read the code, then predictlet size = ""; switch ("medium") { default: size = "unknown"; case "large": size = size + " size"; } console.log(size);Choose an answer to see the explanation.
Question 6 of 7Why might you choose an object lookup instead of a switch?
Choose an answer to see the explanation.
Question 7 of 7What happens when a
returnruns inside a switch inside a function?Choose an answer to see the explanation.
Key takeaways
- A switch reads one value. It compares that value with each case label, the same way
===does: same value and same type. - The code starts at the matching case. It keeps running down until a
break, areturn, or the end of the switch. defaultruns when no case matches. It can go anywhere, and it falls through too if it has nobreak.- Empty cases stacked above one set of lines share those lines. If a case runs its own lines and then falls through on purpose, add a comment.
- Use an object lookup when each key maps straight to a value. Use
if/elsewhen each choice asks a different question.
Remember the one-liner.
A switch jumps to the first case that matches exactly, then runs until something stops it.
Up next: Loops: while & for. You'll repeat code many times, and you'll see that break can end a loop too.