The switch statement
Choose between many JavaScript cases with strict matching, break, default, intentional fallthrough, and object lookup alternatives.
- 01Match cases exactlyExplain why switch uses the same strict matching idea as ===.
- 02Control fallthroughUse break, intentional grouped cases, return, and default safely.
- 03Choose the cleaner patternDecide between switch, if/else chains, and object lookups.
Choose one path from many exact cases
INTERACTIVEThe switch statement is a control-flow tool for one common shape of decision: you have one value, and you want to jump to one of several named cases. It is a cousin of an if / else if chain, but it reads best when the question is “Which exact value is this?”
You already met comparisons, including the difference between === and ==. A switch uses strict matching like ===. You also saw in Type conversion that inputs usually arrive as strings. Those two facts matter here: the string "1" will not match the number case 1.
Imagine typing B3 into a vending machine. The machine does not inspect A1, A2, A3, and slowly wander downward. It jumps straight to the matching slot. A switch has the same feel: one value, a menu of exact labels, and one starting point.
- In real life: You press B3
- In JavaScript:
switch (slot)evaluates one value - In real life: The machine jumps to slot B3
- In JavaScript: JavaScript jumps to the matching
case - In real life: A sold-out or wrong code needs a fallback
- In JavaScript:
defaulthandles none of the above - In real life: The snack drops and the action is done
- In JavaScript:
breakorreturnends that branch
Where the analogy stops: A vending machine stops automatically after one snack. JavaScript does not: without break or return, it can keep running into the next case.
Here is the shape you will practice throughout the lesson:
switch (value) { case "first": // statements for first break; case "second": // statements for second break; default: // statements when no case matched}The important rule is not “run one block.” The actual rule is: find the first matching case, then run statements downward until something stops the switch. Most of the lesson is about what counts as a match, and what stops the downward flow.
Matching with strict equality
TRY ITEvery case label is compared with the switch value using strict matching, the same idea as ===. JavaScript does not helpfully convert strings to numbers for you while choosing a case.
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. The first case is the number 1, but the switch value is the string "1". The second case has the same type and value, so it matches.
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" (string). It chooses "string one".
If a prompt, URL parameter, or form field gives you text, decide what type your cases should use. Convert once with Number(input) when your cases are numbers, or write string cases when the codes are meant to be text.
You may see a pattern called switch (true) for ranges:
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);This works because each case expression produces a boolean, and the first true case matches switch (true). Use it sparingly. For most beginner code, a normal if / else if chain is clearer for ranges because each line is visibly a condition.
break and fallthrough
STEP THROUGHA switch does not automatically stop at the next case label. Once a match is found, JavaScript keeps running statements downward. A break statement exits the switch.
Picture a staircase in the rain. Once water lands on one step, it keeps flowing down to the next step unless something blocks it. Switch execution is the same: a matching case is the step where execution begins, not a sealed room.
- In real life: Water lands on a stair
- In JavaScript: Execution starts at the matching case
- In real life: It flows to lower stairs
- In JavaScript: Statements below also run
- In real life: A dam stops the water
- In JavaScript:
breakexits the switch - In real life: No dam means the next step gets wet
- In JavaScript: Missing
breakmeans fallthrough
Where the analogy stops: Water has no intention. Code can use fallthrough intentionally, but you must make that intention obvious.
Use this recorded replay to see the difference. Pick yellow, then remove yellow’s break. The same input changes from slow down to go because the green case runs after yellow.
Pick a color, then step through the real switch. Try yellow with and without the break to see fallthrough.
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);Grouping cases is common and safe when the earlier cases have no statements. If you intentionally run statements and then fall into a later case, add a comment like // falls through. ESLint’s no-fallthrough rule respects that convention; the Linting lesson explains why teams use rules like this.
default is the none-of-the-above case
EDGE CASESThe default label runs when no case matched. It is the “none of the above” button. Most examples place it last because that is easiest to read, but JavaScript allows it anywhere.
const size = "large";let price; switch (size) { default: price = "ask staff"; break; case "small": price = 3; break; case "large": price = 5;} console.log(price);With size set to "large", JavaScript skips the middle default and matches case "large". The output is 5. Default’s position did not make it run first.
But default follows the same fallthrough rules as every other label:
const size = "medium";let price = ""; switch (size) { default: price = "unknown"; case "large": price = price + " size";} console.log(price);Here "medium" matches no case, so default runs and sets price to "unknown". There is no break, so execution continues into the "large" case body and appends " size". The output is unknown size.
Practical switch patterns
PATTERNSThe safest fallthrough is an empty case that groups several labels before one shared body. Days of the week are a classic example:
const day = "Saturday";let kind; switch (day) { case "Saturday": case "Sunday": kind = "weekend"; break; default: kind = "weekday";} console.log(kind);Saturday has no statements of its own, so it falls into Sunday’s shared body. That is intentional and easy to read. The shared body still ends with break.
A switch inside a function often returns from each case. A return exits the whole function, so it also prevents fallthrough:
function shipping(speed) { switch (speed) { case "overnight": return 25; case "standard": return 7; default: return 0; }} console.log(shipping("standard"));This prints 7. Once return 7 runs, the function is done. A break after that return would be unreachable.
You will use switches for small menus: keyboard commands, status strings, route names, display modes, and other exact labels. If the list grows large or comes from data, the next section gives you a cleaner alternative.
Object lookups instead of switch
SORTERSometimes a switch is only a long table: this key means that value. For that shape, a simple object literal plus bracket access is often shorter and safer.
const prices = { apple: 1.2, banana: 0.5, cherry: 2,}; const fruit = "banana";const price = prices[fruit] ?? "unknown";console.log(price);prices[fruit] asks the object for the value stored at the key in fruit. If that key is missing, it would produce undefined, so the nullish coalescing operator ?? gives a fallback. Object basics get a full lesson in Stage 3; for now, read the braces as a tiny lookup table. The Map data structure comes later in Map & Set.
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.
| Question | switch | if / else | object lookup |
|---|---|---|---|
| Best question | Which exact value is this? | Which condition is true? | What value belongs to this key? |
| Typical input | A string or number with known cases | Ranges, multiple variables, or truthy checks | A string key like a product name |
| Main risk | Forgetting break and falling through | Putting conditions in the wrong order | Missing keys returning undefined |
| Dynamic data | Awkward: cases are written in code | Awkward for long lists | Great: the object can be created or updated |
| Beginner rule | Use it for a short menu of exact choices | Use it when each branch asks a different question | Use it when keys map directly to values |
- A command can be exactly
copy,paste,cut, orundo. - If temperature is below 0, below 20, or higher.
- Fruit names map directly to prices loaded from data.
- Saturday and Sunday should run the same branch.
- A role name maps to a small handler function.
- Check empty name, invalid email, then short password in order.
Sort each scenario by the clearest decision shape. There can be working alternatives, but choose the one that reads best for a beginner maintaining the code.
Common misconceptions
“switch uses loose equality.”
It does not. case 1 will not match "1". Convert the value first or use string cases.
“Only the matching case runs.”
The matching case is where execution starts. Statements below can run too unless break, return, or the end of the switch stops them.
“default must be last.”
It can appear anywhere. Last is usually clearest, and it still follows fallthrough rules.
“Fallthrough is always a bug.”
Missing break is often a bug, but grouped cases like Saturday and Sunday intentionally share a body. Add a comment when non-empty fallthrough is deliberate.
“Each case has its own block automatically.”
Cases share the switch block. That means two let declarations with the same name can clash before any case runs.
switch ("a") { case "a": let message = "alpha"; break; case "b": let message = "bravo"; break;}switch ("a") { case "a": { let message = "alpha"; console.log(message); break; } case "b": { let message = "bravo"; console.log(message); break; }}If a case declares let or const, wrap that case body in braces. It makes the scope visible and prevents future declarations from colliding.
Practice: trace and refactor switches
5 EXERCISESFor prediction exercises, do not run the code first. Find the matching case, then read downward until a stop. After you answer, paste it into your console to prove it.
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. Because there is no break, the bronze case runs next and appends + Bronze. The final log is Silver + Bronze.
"1" versus 1 mismatchFirst predict what the buggy code prints. Then change it so the first page is selected.
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 original prints not found because the string "1" does not strictly match number 1. Converting once with Number(input) makes the number case match and print first.
Write or explain a switch where Saturday and Sunday both produce 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);Saturday has no body, so it intentionally falls through to Sunday's shared body. Both days set kind to weekend, then break exits the switch.
Refactor the function without changing its behavior. It should still return ❓ for an unknown status.
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 names to icons. Bracket access reads the selected icon, and ?? supplies the same default as the switch. For warning, both versions print ⚠️.
Add a fallback so unknown drink size codes return 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"));The default branch catches any 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 exactly. Your first-try score matters less than the explanation after each choice.
Question 1 of 7How does
switchcompare its value with eachcase?Choose an answer to see the explanation.
Question 2 of 7What does strict matching print here?
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 7What does the missing break 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 7Which is the clearest way to handle
SaturdayandSundaythe same way?Choose an answer to see the explanation.
Question 5 of 7What does default fallthrough 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 evaluates one value, then compares it to case labels using strict matching like
===. - Execution starts at the matching case and continues downward until
break,return, or the end of the switch. defaultruns when no case matches. It can be placed anywhere, but it can also fall through if you omitbreak.- Grouped empty cases are a clear way to share one body; non-empty intentional fallthrough needs a comment.
- Use object lookups when keys map directly to values. Use
if/elsewhen each branch asks a different condition.
Remember the one-liner.
A switch jumps to the first strictly matching case, then runs until something stops it.
Up next: Loops: while & for. You will repeat work and see that break can exit loops too.