switch Statement

โ–ถ Try It Yourself

The switch statement is the right tool when a single variable or expression needs to be compared against multiple specific values. While a chain of else if statements can do the same job, switch is cleaner and more expressive when you have three or more distinct cases. In this lesson you will master switch syntax, the critical role of break, fall-through behaviour, and the modern object-map pattern that often replaces switch entirely.

switch vs if/else if

Feature switch else if chain
Best for One variable vs many fixed values Complex, range-based, or mixed conditions
Comparison type Strict equality (===) only Any boolean expression
Fall-through Yes โ€” cases run into the next without break No โ€” only one branch runs
Default case default: block Final else block
Readability at 5+ cases Better โ€” clear tabular structure Worse โ€” long chain of else ifs

switch Anatomy

Part Purpose Required?
switch (expression) Evaluates expression once; compares to each case Yes
case value: Matches when expression === value At least one
break; Exits the switch block โ€” prevents fall-through Almost always
default: Runs when no case matches โ€” like else Recommended
Fall-through (intentional) Omit break to let multiple cases share one block Use with care + comment

Modern Alternatives to switch

Pattern Syntax Best For
Object map const map = { key: value }; map[input] ?? default Mapping values to results โ€” cleanest pattern
Map object new Map([[key, value]]) Non-string keys or complex values
switch (classic) switch (x) { case 'a': ... } Multiple cases sharing one block (fall-through)
Note: switch uses strict equality (===) for comparisons โ€” just like you should be using in your if statements. This means switch will NOT match a string '1' to a number 1. Always make sure the type of your switch expression matches the type of your case values.
Tip: For simple value-to-result mappings, an object lookup is often cleaner than switch: const labels = { en: 'English', fr: 'French', de: 'German' }; const label = labels[lang] ?? 'Unknown';. This is more concise, easily extensible (just add a key), and can be stored in a config file or fetched from an API.
Warning: Forgetting break is one of the most common JavaScript bugs. Without it, execution falls through to the next case and runs it too โ€” even if that case’s value did not match. Always add break at the end of every case unless you have intentionally written a fall-through with a comment explaining why.

Basic Example

// โ”€โ”€ Basic switch โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
function getDayName(dayNumber) {
    switch (dayNumber) {
        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(getDayName(3));   // 'Wednesday'
console.log(getDayName(6));   // 'Saturday'
console.log(getDayName(9));   // 'Invalid day'

// โ”€โ”€ switch with break (without return) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
function describeWeather(condition) {
    let advice;

    switch (condition) {
        case 'sunny':
            advice = 'Wear sunscreen and sunglasses.';
            break;
        case 'rainy':
            advice = 'Bring an umbrella.';
            break;
        case 'snowy':
            advice = 'Dress in warm layers.';
            break;
        case 'windy':
            advice = 'Secure loose items outside.';
            break;
        default:
            advice = 'Check the forecast before heading out.';
    }

    return advice;
}

console.log(describeWeather('rainy'));    // 'Bring an umbrella.'
console.log(describeWeather('cloudy'));   // 'Check the forecast...'

// โ”€โ”€ Intentional fall-through โ€” multiple cases, same block โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
function isWeekend(day) {
    switch (day.toLowerCase()) {
        case 'saturday':
        case 'sunday':
            // FALL-THROUGH: both Saturday and Sunday are weekends
            return true;
        default:
            return false;
    }
}

console.log(isWeekend('Saturday'));  // true
console.log(isWeekend('Monday'));    // false

// โ”€โ”€ Object map โ€” modern alternative to switch โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
const HTTP_MESSAGES = {
    200: 'OK',
    201: 'Created',
    400: 'Bad Request',
    401: 'Unauthorised',
    403: 'Forbidden',
    404: 'Not Found',
    500: 'Internal Server Error',
};

function getHttpMessage(code) {
    return HTTP_MESSAGES[code] ?? `Unknown status code: ${code}`;
}

console.log(getHttpMessage(200));   // 'OK'
console.log(getHttpMessage(404));   // 'Not Found'
console.log(getHttpMessage(418));   // 'Unknown status code: 418'

// โ”€โ”€ switch on string with transformation โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
function getRoleLabel(role) {
    switch (role?.toLowerCase().trim()) {
        case 'admin':        return 'Administrator';
        case 'editor':       return 'Content Editor';
        case 'viewer':       return 'Read-Only Viewer';
        case 'guest':        return 'Guest User';
        default:             return 'Unknown Role';
    }
}

console.log(getRoleLabel('ADMIN'));    // 'Administrator'
console.log(getRoleLabel('  editor ')); // 'Content Editor'
console.log(getRoleLabel(null));       // 'Unknown Role'

How It Works

Step 1 โ€” Expression Is Evaluated Once

The expression in switch (expression) is evaluated exactly once at the start. JavaScript then walks through each case comparing the result with ===. This is why transforming the expression โ€” like role?.toLowerCase().trim() โ€” is done inside the switch parentheses, not repeated in every case.

Step 2 โ€” break Exits the switch Block

When JavaScript finds a matching case, it executes every statement from that point onwards until it hits a break, a return, or the end of the switch block. Without break, execution “falls through” into the next case’s code โ€” even if that case’s value does not match.

Step 3 โ€” Intentional Fall-Through Groups Cases

Placing multiple case labels consecutively with no code between them creates intentional fall-through โ€” all those cases share the same block. The isWeekend example uses this: both 'saturday' and 'sunday' fall through to the same return true. Always add a comment when doing this intentionally.

Step 4 โ€” default Is the Fallback

The default case runs when no other case matches โ€” equivalent to the final else. It does not need to be last (JavaScript will still try all cases first), but placing it last is a strong convention for readability.

Step 5 โ€” Object Maps Are Often Cleaner

The HTTP_MESSAGES object demonstrates the object-map pattern: store the mapping as data, not logic. Lookup is a single line: HTTP_MESSAGES[code] ?? fallback. This is faster to read, trivially extensible, and can be imported from a separate config file โ€” none of which is true for a switch block.

Real-World Example: Notification Router

// notification-router.js

// Object map for simple type-to-config lookups
const NOTIFICATION_CONFIG = {
    success: { icon: 'check-circle', colour: '#10b981', duration: 3000 },
    error:   { icon: 'x-circle',     colour: '#ef4444', duration: 6000 },
    warning: { icon: 'alert-circle',  colour: '#f59e0b', duration: 4000 },
    info:    { icon: 'info',          colour: '#3b82f6', duration: 3000 },
};

function createNotification(type, message) {
    const config = NOTIFICATION_CONFIG[type] ?? NOTIFICATION_CONFIG.info;

    return {
        id:       `notif-${Date.now()}`,
        type,
        message,
        icon:     config.icon,
        colour:   config.colour,
        duration: config.duration,
    };
}

// switch for action dispatch โ€” fall-through used intentionally
function handleKeyboardShortcut(key, ctrlKey) {
    switch (true) {
        case (ctrlKey && key === 's'):
            return 'save';
        case (ctrlKey && key === 'z'):
            return 'undo';
        case (ctrlKey && key === 'y'):
        case (ctrlKey && key === 'Z'): // Ctrl+Shift+Z also = redo
            // INTENTIONAL FALL-THROUGH: both shortcuts trigger redo
            return 'redo';
        case (key === 'Escape'):
            return 'close';
        case (key === 'F1'):
            return 'help';
        default:
            return null;
    }
}

console.log(createNotification('success', 'File saved!'));
console.log(createNotification('error',   'Upload failed.'));
console.log(handleKeyboardShortcut('s', true));      // 'save'
console.log(handleKeyboardShortcut('Escape', false)); // 'close'
console.log(handleKeyboardShortcut('a', false));      // null

Common Mistakes

Mistake 1 โ€” Forgetting break causes fall-through

โŒ Wrong โ€” missing break means case ‘b’ code also runs when input is ‘a’:

switch (input) {
    case 'a':
        console.log('A');   // runs for input 'a'
        // no break!
    case 'b':
        console.log('B');   // ALSO runs for input 'a' โ€” unintended!
        break;
}

โœ… Correct โ€” break after every case that should not fall through:

switch (input) {
    case 'a':
        console.log('A');
        break;  // stops here
    case 'b':
        console.log('B');
        break;
}

Mistake 2 โ€” Using switch for range comparisons

โŒ Wrong โ€” switch cannot match ranges, only exact values:

switch (score) {
    case score >= 90: return 'A';  // always false โ€” compares number to boolean
}

โœ… Correct โ€” use if/else for range-based logic:

if (score >= 90) return 'A';
else if (score >= 80) return 'B';

Mistake 3 โ€” Type mismatch between expression and cases

โŒ Wrong โ€” switch uses ===, string ‘1’ does not match number 1:

const input = '1';  // string from HTML input
switch (input) {
    case 1: console.log('one'); break;  // never matches โ€” '1' !== 1
}

โœ… Correct โ€” convert type before switching or match string case values:

switch (Number(input)) {
    case 1: console.log('one'); break;  // now matches
}

▶ Try It Yourself

Quick Reference

Pattern Example Notes
Basic switch switch (x) { case 'a': ... break; } Always add break
Default case default: ... Runs when nothing matches
Intentional fall-through Two case labels, no code between them Add comment explaining intent
switch(true) case (x > 10): Lets you use expressions in cases
Object map const m = {a:1, b:2}; m[x] ?? def Cleaner than switch for simple lookups

🧠 Test Yourself

What happens if you omit break at the end of a matching case in a switch statement?





โ–ถ Try It Yourself