JavaScriptSwitch

switch

The switch statement compares a single value against a list of possibilities and runs the block that matches. When you have more than two or three branches that all check the same variable, switch is usually cleaner than an else if chain — but it has a few sharp edges that catch every JavaScript developer at least once.

Basic syntax

The shape is switch (value) { case x: ... break; ... default: ... }. The comparison uses strict equality (===), so 1 and "1" are different cases.

JS
function dayName(n) {
  switch (n) {
    case 0: return "Sunday";
    case 1: return "Monday";
    case 2: return "Tuesday";
    case 3: return "Wednesday";
    case 4: return "Thursday";
    case 5: return "Friday";
    case 6: return "Saturday";
    default: return "Invalid day";
  }
}

console.log(dayName(3));   // Wednesday
console.log(dayName(9));   // Invalid day
Wednesday
Invalid day

The return in each case ends the function, so we don't need break. In a statement form (no return) you need break to stop fall-through.

Fall-through — feature or trap?

If a case block does not end with break, return, throw or continue, execution falls through into the next case. This is sometimes intentional and often a bug.

Accidental fall-through

JS
switch (color) {
  case "red":
    console.log("stop");
  case "yellow":            // forgot break above
    console.log("slow");
  case "green":
    console.log("go");
}
// color = "red" prints all three lines.

Deliberate fall-through — grouping cases

JS
function isWeekend(day) {
  switch (day) {
    case "Saturday":
    case "Sunday":
      return true;
    default:
      return false;
  }
}

Stacking empty cases is the cleanest way to say any of these. When you intentionally fall through with code in between, a comment like // fall through makes the intent clear to readers and to linters.

ESLint will yell — listen to it
The `no-fallthrough` rule flags every case that doesn't explicitly terminate. Disable it only when fall-through is *deliberate*, and document why.
Default placement

default runs when no case matches. It can appear anywhere in the switch — but conventionally goes last because that is where readers expect it. Wherever you put it, the break rules still apply.

JS
switch (status) {
  case "loading":  showSpinner();   break;
  case "error":    showError();     break;
  case "success":  showResult();    break;
  default:         showUnknown();   // last, no break needed (nothing after)
}
Block scoping with braces

Cases share a single scope by default, so declaring let or const with the same name in two cases is a SyntaxError. Wrap each case in its own { ... } to fix it.

Without braces — name collision

JS
switch (kind) {
  case "user":
    let id = user.id;             // declared here
    console.log(id);
    break;
  case "post":
    let id = post.id;             // SyntaxError: 'id' already declared
    break;
}

With braces — each case has its own scope

JS
switch (kind) {
  case "user": {
    const id = user.id;
    console.log(id);
    break;
  }
  case "post": {
    const id = post.id;
    console.log(id);
    break;
  }
}
Braces by default
Even when you don't declare anything, wrapping each case in braces makes future edits safer. It costs you two characters and saves the next developer a confused minute.
When switch beats if-else

Reach for switch when all of the following are true: you are testing one value, you are testing for equality, and you have at least three or four cases. In those situations the structure tells the reader "we are dispatching on this one variable", which an else if chain hides.

A small reducer-style dispatcher

JS
function reducer(state, action) {
  switch (action.type) {
    case "INCREMENT": return { ...state, count: state.count + 1 };
    case "DECREMENT": return { ...state, count: state.count - 1 };
    case "RESET":     return { ...state, count: 0 };
    case "SET":       return { ...state, count: action.value };
    default:          return state;
  }
}

Use if/else instead when conditions involve ranges, multiple variables, or non-equality checks (<, >, instanceof, startsWith).

The lookup object alternative

When every case maps a value to another value (no real branching logic), a plain object is shorter and easier to extend than a switch.

JS
const ICONS = {
  loading: "spinner.svg",
  success: "check.svg",
  error:   "x.svg",
};

function iconFor(status) {
  return ICONS[status] ?? "unknown.svg";
}
Three flavours, one job
`if/else`, `switch` and lookup objects all dispatch on a value. Pick `if/else` for compound conditions, `switch` for grouped equality cases with side effects, and a lookup table when you are mapping values to values.
Pattern-style switching with true

A neat trick: switch (true) lets each case carry its own boolean expression. It is a way to get range checks inside a switch, but most teams find it surprising — use sparingly.

JS
function grade(score) {
  switch (true) {
    case score >= 90: return "A";
    case score >= 75: return "B";
    case score >= 50: return "C";
    default:          return "F";
  }
}
One sentence to remember
Use `switch` for "this one value, equal to which of these?" — everything else is probably an `if/else` chain or a lookup table.