Command Palette

Search for a command to run...

Hectal
PHASE 2Beginner ~20 min· topic 4 of 7

Topic 2.4

switch Statements

In one line

switch compares one value against a list of case values with === and jumps to the first match; execution then falls through into the next cases until a break, and default handles no match. For pure value-to-value mapping, an object or Map is often better.

Think of it like this

A lift (elevator). You press one floor button. The lift goes straight to that floor, not to every floor asking "is it this one?". If the doors didn't close at your floor (no break), you'd keep going up through the next floors too. And if you press a floor that doesn't exist, you end up at the ground floor (the default).

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

switch
A statement that compares one value against several case values and jumps to the matching one.
case
A label inside a switch with a value to compare against; matching is done with ===.
Discriminant
The value in switch (...) that every case is compared to. It's evaluated once.
Fall-through
Running on from one case into the next because there was no break.
break
A statement that leaves the switch (or a loop) immediately.
default
The part of a switch that runs when no case matched.
Lookup table
An object or Map that maps each input value to its result, used instead of a switch.

Step by step

01The basic shape

One value, several cases, a break after each, and a default for anything else.

switch.jswhole filejavascript
const light = "amber";
switch (light) {
  case "green":
    console.log("Go");
    break;
  case "amber":
    console.log("Get ready to stop");
    break;
  case "red":
    console.log("Stop");
    break;
  default:
    console.log("Signal broken: stop and look");
}

02How the jump works

The engine evaluates light once, then compares it with each case value using === until one matches. It jumps there and runs everything below until a break.

How the jump worksdiagram
Rendering diagram…

03Group cases on purpose

Stack case labels with nothing between them to give several values the same code. This is the useful side of fall-through.

group.jswhole filejavascript
switch (day) {
  case "Sat":
  case "Sun":
    console.log("Weekend");
    break;
  default:
    console.log("Weekday");
}

04Give cases their own block when they declare variables

All cases share one scope. Braces after the case label give each case its own, so names can't clash.

blocks.jswhole filejavascript
switch (shape) {
  case "square": {
    const area = side * side;
    console.log(area);
    break;
  }
  case "circle": {
    const area = Math.PI * r * r;
    console.log(area);
    break;
  }
}

05Replace value-only switches with a table

When each case only maps a value, a Map (or an object) does the job in a few lines, and adding a new size means adding data, not code.

lookup.jswhole filejavascript
const prices = new Map([
  ["small", 50],
  ["medium", 80],
  ["large", 120],
]);
console.log(prices.get("medium") ?? 0); // 80

Try it yourself

  1. 1

    Remove a break on purpose

    In the first example, delete the break; under "Fri". Predict what Friday's plan becomes, then choose Fri in the menu. (Work and study: it fell through into the next case.)

  2. 2

    Fix the type mismatch

    In the second example, change switch (input) to switch (Number(input)) and predict the output.

  3. 3

    Add an action

    In the third example, add half: (n) => n / 2 to actions and set command to "half". You added a feature with data, not a new case.

Code & diagrams

A switch with grouped cases and a default New tab

Pick another day in the menu. Stacked case labels share one block of code.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

Rest and play | Work, then movie night | Work and study | Unknown day
Fall-through and strict matching New tab

With no `break`, case 1 runs on through 2 and 3 until the `break`. And `switch` uses `===`, so the string `"2"` never matches the number `2`.

Console

(nothing was printed)

Expected console output

bronze
silver
gold
no match: '2' !== 2
Lookup tables instead of switch ES2022+ New tab

`prices["constructor"]` finds a function every object inherits. `Object.hasOwn` (ES2022) or a `Map` (ES2015) only accept keys you added yourself.

Console

(nothing was printed)

Expected console output

80
0
function
unknown size
0
49

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Declare the same variable in two cases

Write a switch where case 1: contains let msg = "one"; and case 2: contains let msg = "two";, without braces.

terminal
$ Console
── what you'll see ──
Uncaught SyntaxError: Identifier 'msg' has already been declared

Break #2

Forget a break

In the first example, delete the break; after plan = "Rest and play"; and choose Sat.

terminal
$ Page
── what you'll see ──
Work, then movie night (on a Saturday)

Myth vs fact

Myth

switch compares with ==, so "2" matches 2.

Fact

It uses strict equality (===). Convert the value first if it comes from text.

Myth

Only the matching case runs.

Fact

Execution starts at the matching case and keeps going through the following cases until a break, return or the end.

Myth

switch is always faster than if/else.

Fact

Engines may turn a dense integer or string switch into a jump table, but for a handful of cases the difference is negligible. Choose by readability.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    The spec evaluates case expressions lazily: each case expression is only evaluated when the matching reaches it. Case values can be any expression (case LIMIT * 2:), not only literals, but non-constant cases prevent engines from building jump tables.

  • ▸

    In TypeScript, a switch over a union type with a default that assigns the value to never gives exhaustiveness checking: adding a new variant makes the compiler show you every switch that doesn't handle it. That's a strong reason to keep switch for state machines and reducers (for example Redux reducers switch on action.type).

  • ▸

    Map beats a plain object as a lookup table when keys aren't strings, when entries change at runtime, or when keys come from users (no prototype keys like __proto__ or constructor). Object.create(null) gives a prototype-less object if you prefer object syntax.

  • ▸

    A TC39 proposal for pattern matching (match) aims to replace many switch uses with destructuring-aware cases, but it is not part of the language as of 2026; don't rely on it.

Remember this

  1. 1

    A switch statement takes one expression in parentheses, the discriminant, evaluates it once, and compares the result with each case value from top to bottom using strict equality (===, Topic 1.6). So switch ("1") does not match case 1:: a string and a number are never ===. When a case matches, execution jumps to that case label and runs the statements after it.

  2. 2

    Fall-through: a case is only a starting point, not a box. After the matching case's statements, execution continues straight into the next case's statements, and the next, until it meets a break (which exits the switch), a return (which exits the whole function) or the end of the switch. Forgetting break is the most common switch bug. Fall-through is useful on purpose when several values share one action: write the cases one after another with no code between them (case "Sat": case "Sun": ...).

  3. 3

    default: runs when no case matched. It's optional, but including it (even just to log or throw on an unexpected value) catches bugs early. It's conventionally last; if you put it elsewhere, it's still only chosen when nothing else matched, but it can fall through into the cases below it. A switch with no matching case and no default does nothing at all.

  4. 4

    Scope trap: the whole body of a switch is one block. Declaring let x in two different cases is a SyntaxError ("already been declared"), and a let from one case is visible, but uninitialised, in the others. Wrap each case's code in its own braces, case 1: { let x = ...; break; }, whenever it declares variables.

  5. 5

    When to prefer objects or Maps: if every case only returns or assigns a value ("small" → 50, "medium" → 80), a lookup table is shorter, has no break to forget and can be changed as data: const prices = { small: 50, medium: 80 }; const p = prices[size] ?? 0;. A plain object inherits keys like toString and constructor, so an unexpected input could match them; use Object.hasOwn(prices, size) (ES2022), Object.create(null), or a **Map** (ES2015), whose get returns undefined for anything you didn't put in. You can even store functions in a lookup table to map values to actions. Keep switch for cases that run different statements, or need fall-through.

  6. 6

    A pattern you'll see is switch (true) with conditions as cases: case score >= 90:. It works because each case expression is evaluated and compared with true, but an if / else if chain says the same thing more plainly (Topic 2.3).

Explain it without notes

01

How does switch decide which case matches?

02

What is fall-through, and when is it useful?

03

When would you use an object or Map instead of a switch?

04

Why can declaring let inside a case cause an error, and how do you fix it?

Practice

01

Write a switch that turns a number 1 to 3 into gold, silver, bronze, and anything else into no medal. Print the result for 2 and 7.

02

Rewrite the medal mapping as a lookup with a fallback, so there is no switch at all.

Trade-offs

  • ↔

    switch reads well for a fixed set of actions and supports fall-through; lookup tables are better for data-like mappings and are easier to extend.

  • ↔

    A Map is safest for arbitrary keys; a plain object is shorter to write and fine for fixed, known string keys checked with Object.hasOwn.

Done when you can

  • I can write a switch with break and default.

  • I know switch matches with ===.

  • I can use fall-through on purpose to group cases, and spot accidental fall-through.

  • I can wrap a case in braces when it declares variables.

  • I can replace a value-mapping switch with an object or Map.