Episode 1 — Fundamentals / 1.19 — Conditionals and Loops
1.19.b -- Switch Statement
In one sentence: The
switchstatement compares one expression against manycasevalues using strict equality (===), executing the matched branch until abreak(or the end), with an optionaldefaultfallback for unmatched values.
Navigation: <-- 1.19.a -- If/Else Branching . 1.19.c -- For Loop -->
1. Basic switch syntax
switch (expression) {
case value1:
// code if expression === value1
break;
case value2:
// code if expression === value2
break;
default:
// code if no case matched
}
How it works step by step:
- Evaluate
expressiononce. - Compare the result to each
casevalue using===(strict equality -- no type coercion). - If a match is found, execute code from that
casedownward until abreakor the end of the switch. - If no case matches and a
defaultexists, execute thedefaultblock.
const day = "Tuesday";
switch (day) {
case "Monday":
console.log("Start of the work week.");
break;
case "Tuesday":
console.log("Second day."); // <-- this runs
break;
case "Friday":
console.log("Almost weekend!");
break;
default:
console.log("Just another day.");
}
// Output: "Second day."
2. The default case
The default case handles any value not matched by a case. It is optional but strongly recommended.
function getStatusText(code) {
switch (code) {
case 200: return "OK";
case 301: return "Moved Permanently";
case 404: return "Not Found";
case 500: return "Internal Server Error";
default: return `Unknown status: ${code}`;
}
}
console.log(getStatusText(200)); // "OK"
console.log(getStatusText(418)); // "Unknown status: 418"
Placement: default is usually last, but it can appear anywhere. The spec allows it -- but putting it last is the universal convention.
3. Fall-through behavior
When a case matches and there is no break, execution falls through into the next case's code. This is the most common source of bugs -- and occasionally an intentional feature.
Accidental fall-through (bug)
const fruit = "apple";
switch (fruit) {
case "apple":
console.log("You picked an apple.");
// BUG: missing break!
case "banana":
console.log("You picked a banana.");
break;
case "cherry":
console.log("You picked a cherry.");
break;
}
// Output:
// "You picked an apple."
// "You picked a banana." <-- unintended!
Intentional fall-through (grouping)
const day = "Saturday";
switch (day) {
case "Monday":
case "Tuesday":
case "Wednesday":
case "Thursday":
case "Friday":
console.log("Weekday -- time to work.");
break;
case "Saturday":
case "Sunday":
console.log("Weekend -- time to rest.");
break;
}
// Output: "Weekend -- time to rest."
When using intentional fall-through, add a comment so other developers know it is deliberate:
case "Saturday": // fall-through intentional
case "Sunday":
console.log("Weekend");
break;
4. Grouping multiple cases
Grouping is the most practical use of fall-through. Stack cases that share the same handler:
function getQuarter(month) {
switch (month) {
case 1: case 2: case 3:
return "Q1";
case 4: case 5: case 6:
return "Q2";
case 7: case 8: case 9:
return "Q3";
case 10: case 11: case 12:
return "Q4";
default:
return "Invalid month";
}
}
console.log(getQuarter(5)); // "Q2"
console.log(getQuarter(11)); // "Q4"
5. switch vs if-else -- when to prefer each
| Criteria | Prefer switch | Prefer if-else |
|---|---|---|
| Comparison type | Single expression against many discrete values | Range checks, complex boolean logic |
| Readability | Cleaner when 3+ exact matches | Better for >=, <, &&, || conditions |
| Equality | Always === (strict) | You choose the operator |
| Action on match | Same structure per case | Different shapes of logic per branch |
| Grouping | Easy via fall-through | Requires || chains |
// switch is ideal here -- many exact matches
switch (command) {
case "start": startGame(); break;
case "pause": pauseGame(); break;
case "reset": resetGame(); break;
default: console.log("Unknown command");
}
// if-else is better here -- range logic
if (temp > 35) {
console.log("Hot");
} else if (temp > 20) {
console.log("Warm");
} else {
console.log("Cold");
}
6. Using switch with different types
Strings
function getColorHex(color) {
switch (color.toLowerCase()) {
case "red": return "#FF0000";
case "green": return "#00FF00";
case "blue": return "#0000FF";
default: return null;
}
}
Numbers
function diceRoll(value) {
switch (value) {
case 1: return "one";
case 2: return "two";
case 3: return "three";
case 4: return "four";
case 5: return "five";
case 6: return "six";
default: return "invalid die face";
}
}
Expressions in case (advanced)
The case clause can hold expressions, not just literals. The switch evaluates them.
const x = 15;
switch (true) { // compare each case to `true`
case x < 10:
console.log("Small");
break;
case x < 20:
console.log("Medium"); // runs -- (15 < 20) === true
break;
case x < 30:
console.log("Large");
break;
}
This switch (true) pattern mimics if-else chains inside a switch. It works but is generally less clear than plain if-else.
7. Common mistake: forgetting break
This is the number-one switch bug. Linters like ESLint have the no-fallthrough rule to catch it.
// BUG
function getLabel(role) {
let label;
switch (role) {
case "admin":
label = "Administrator";
// missing break -- falls through
case "editor":
label = "Editor"; // overwrites "Administrator"!
break;
case "viewer":
label = "Viewer";
break;
}
return label;
}
console.log(getLabel("admin")); // "Editor" -- WRONG
Fix: Always include break (or return) at the end of each case block.
function getLabel(role) {
switch (role) {
case "admin": return "Administrator";
case "editor": return "Editor";
case "viewer": return "Viewer";
default: return "Unknown";
}
}
Using return instead of break inside functions is often cleaner -- you exit the function immediately.
8. Block scoping inside cases
If you declare variables with let or const inside a case, wrap the case body in { } to create a block scope. Otherwise, two cases sharing the same switch scope will conflict.
switch (action) {
case "create": {
const item = buildItem(data); // scoped to this block
save(item);
break;
}
case "delete": {
const item = findItem(id); // no conflict with the above
remove(item);
break;
}
}
Without the braces, const item in the first case would conflict with const item in the second case (same block scope = SyntaxError).
9. Real-world examples
Example 1 -- HTTP status codes
function handleResponse(status) {
switch (status) {
case 200:
case 201:
console.log("Success!");
break;
case 301:
case 302:
console.log("Redirecting...");
break;
case 400:
console.log("Bad request. Check your input.");
break;
case 401:
case 403:
console.log("Authentication / authorization error.");
break;
case 404:
console.log("Resource not found.");
break;
case 500:
console.log("Server error. Try again later.");
break;
default:
console.log(`Unhandled status code: ${status}`);
}
}
Example 2 -- Menu selection
function executeMenuChoice(choice) {
switch (choice) {
case 1:
console.log("Opening new file...");
break;
case 2:
console.log("Saving current file...");
break;
case 3:
console.log("Printing...");
break;
case 4:
console.log("Exiting application.");
break;
default:
console.log("Invalid choice. Please select 1-4.");
}
}
Example 3 -- Day type classifier
function classifyDay(day) {
switch (day.toLowerCase()) {
case "monday":
return { type: "weekday", energy: "low", tip: "Ease into the week." };
case "tuesday":
case "wednesday":
case "thursday":
return { type: "weekday", energy: "medium", tip: "Deep work hours." };
case "friday":
return { type: "weekday", energy: "winding down", tip: "Wrap up loose ends." };
case "saturday":
case "sunday":
return { type: "weekend", energy: "recharge", tip: "Rest and hobbies." };
default:
throw new Error(`Unknown day: ${day}`);
}
}
Key takeaways
switchcompares with===-- no type coercion.break(orreturn) is required after each case to prevent fall-through.- Intentional fall-through is useful for grouping cases with the same handler -- add a comment.
- Use
switchwhen comparing one expression against many discrete values; useif-elsefor ranges or complex logic. - Wrap case bodies in
{ }when declaringlet/constvariables.
Explain-It Challenge
Explain without notes:
- What happens if you omit
breakfrom a matchingcase? - Does
switchuse==or===? Why does this matter forswitch ("1") { case 1: ... }? - Rewrite a three-case switch as an equivalent
if-elsechain.
Navigation: <-- 1.19.a -- If/Else Branching . 1.19.c -- For Loop -->