How does the switch operator work in JavaScript and how does comparison happen?

👨‍💻 Frontend Developer 🟡 Often Asked 🎚️ Easy
#JavaScript #JS Basics #Conditional

Quick Answer

The switch operator performs strict comparison (===) between the expression and values in case. Does not convert types and uses fall-through mechanism:

const value = "5";
 
switch (value) {
  case 5:        // false ("5" !== 5)
    console.log("Number");
    break;
  case "5":      // true ("5" === "5")
    console.log("String");
    break;
  default:
    console.log("Other");
}
// Output: "String"

Key features: Strict comparison, mandatory break, execution until the first break.


How the switch operator works

Basic syntax

switch (expression) {
  case value1:
    // code for value1
    break;
  case value2:
    // code for value2
    break;
  default:
    // default code
}

Strict comparison (===)

const userInput = "1";
 
switch (userInput) {
  case 1:           // false ("1" !== 1)
    console.log("Number one");
    break;
  case "1":         // true ("1" === "1")
    console.log("String one");
    break;
  case true:        // false ("1" !== true)
    console.log("Boolean");
    break;
}
// Output: "String one"

Comparison with if-else

// Switch uses strict comparison
const value = 0;
 
switch (value) {
  case false:     // false (0 !== false)
    console.log("False");
    break;
  case 0:         // true (0 === 0)
    console.log("Zero");
    break;
}
// Output: "Zero"
 
// Equivalent if-else
if (value === false) {
  console.log("False");
} else if (value === 0) {
  console.log("Zero");
}

Switch vs if comparison table

Valueswitch caseif (==)if (===)Explanation
"5" vs 5falsetruefalseSwitch uses strict comparison
0 vs falsefalsetruefalseNo type coercion in switch
"" vs 0falsetruefalseSwitch doesn’t convert types
null vs undefinedfalsetruefalseStrict comparison in switch
1 vs truefalsetruefalseDifferent types for switch
"hello" vs "hello"truetruetrueIdentical strings
NaN vs NaNfalsefalsefalseNaN is not equal to itself

Fall-Through Mechanism

What is Fall-Through

Fall-through — code execution continues until the first break or end of block:

const day = "monday";
 
switch (day) {
  case "monday":
    console.log("Start of week");
    // NO break! Continue execution
  case "tuesday":
    console.log("Working day");
    break;
  case "saturday":
  case "sunday":
    console.log("Weekend");
    break;
}
 
// Output:
// "Start of week"
// "Working day"

Useful Fall-Through usage

// Grouping cases
function getSeasonByMonth(month) {
  switch (month) {
    case "december":
    case "january":
    case "february":
      return "Winter";
    
    case "march":
    case "april":
    case "may":
      return "Spring";
    
    case "june":
    case "july":
    case "august":
      return "Summer";
    
    case "september":
    case "october":
    case "november":
      return "Autumn";
    
    default:
      return "Unknown month";
  }
}
 
console.log(getSeasonByMonth("january")); // "Winter"

Fall-Through dangers

⚠️ Warning! Forgotten break can lead to unexpected behavior:

// ❌ Error: forgot break
function processGrade(grade) {
  switch (grade) {
    case "A":
      console.log("Excellent!");
      // Forgot break!
    case "B":
      console.log("Good!");
      break;
    case "C":
      console.log("Satisfactory");
      break;
    default:
      console.log("Need improvement");
  }
}
 
processGrade("A");
// Output:
// "Excellent!"
// "Good!" (undesirable!)

Practical Examples

1. HTTP status handling

function handleHttpStatus(status) {
  switch (status) {
    case 200:
    case 201:
    case 204:
      return "Success";
    
    case 400:
      return "Bad Request";
    
    case 401:
      return "Unauthorized";
    
    case 403:
      return "Forbidden";
    
    case 404:
      return "Not Found";
    
    case 500:
    case 502:
    case 503:
      return "Server Error";
    
    default:
      return `Unknown status: ${status}`;
  }
}
 
console.log(handleHttpStatus(200));  // "Success"
console.log(handleHttpStatus("200")); // "Unknown status: 200"

2. Calculator

function calculate(a, operator, b) {
  switch (operator) {
    case "+":
      return a + b;
    
    case "-":
      return a - b;
    
    case "*":
      return a * b;
    
    case "/":
      if (b === 0) {
        throw new Error("Division by zero");
      }
      return a / b;
    
    case "**":
    case "^":
      return Math.pow(a, b);
    
    default:
      throw new Error(`Unknown operator: ${operator}`);
  }
}
 
console.log(calculate(5, "+", 3));  // 8
console.log(calculate(10, "/", 2)); // 5

3. Type validation

function validateInput(value, expectedType) {
  const actualType = typeof value;
  
  switch (expectedType) {
    case "string":
      if (actualType === "string" && value.length > 0) {
        return { valid: true, message: "Valid string" };
      }
      return { valid: false, message: "Expected non-empty string" };
    
    case "number":
      if (actualType === "number" && !isNaN(value)) {
        return { valid: true, message: "Valid number" };
      }
      return { valid: false, message: "Expected number" };
    
    case "boolean":
      if (actualType === "boolean") {
        return { valid: true, message: "Valid boolean" };
      }
      return { valid: false, message: "Expected boolean" };
    
    case "array":
      if (Array.isArray(value)) {
        return { valid: true, message: "Valid array" };
      }
      return { valid: false, message: "Expected array" };
    
    default:
      return { valid: false, message: `Unknown type: ${expectedType}` };
  }
}
 
console.log(validateInput("hello", "string")); // { valid: true, ... }
console.log(validateInput(42, "string"));      // { valid: false, ... }

Practical Tasks

Task 1: What will the console output?

const value = 1;
 
switch (value) {
  case "1":
    console.log("String");
    break;
  case 1:
    console.log("Number");
  case true:
    console.log("Boolean");
    break;
  default:
    console.log("Other");
}
Answer

Output:

Explanation:

  • value = 1 strictly equals case 1, so this block executes
  • No break after case 1, so execution continues
  • Code in case true executes (fall-through)
  • break stops execution

Task 2: Find the error

function getDayType(day) {
  switch (day) {
    case "monday":
    case "tuesday":
    case "wednesday":
    case "thursday":
    case "friday":
      return "Working day";
    case "saturday":
    case "sunday":
      return "Weekend";
  }
}
 
console.log(getDayType("monday")); // ?
console.log(getDayType("MONDAY")); // ?
console.log(getDayType("mon"));    // ?
Answer

Result:

  • getDayType("monday")"Working day"
  • getDayType("MONDAY")undefined
  • getDayType("mon")undefined

Problems:

  1. No default case
  2. Case sensitivity
  3. Doesn’t handle abbreviations

Fixed version:

function getDayType(day) {
  const normalizedDay = day.toLowerCase();
  
  switch (normalizedDay) {
    case "monday":
    case "mon":
    case "tuesday":
    case "tue":
    case "wednesday":
    case "wed":
    case "thursday":
    case "thu":
    case "friday":
    case "fri":
      return "Working day";
    
    case "saturday":
    case "sat":
    case "sunday":
    case "sun":
      return "Weekend";
    
    default:
      return "Unknown day";
  }
}

Task 3: What will the code output?

const score = "85";
 
switch (true) {
  case score >= 90:
    console.log("A");
    break;
  case score >= 80:
    console.log("B");
    break;
  case score >= 70:
    console.log("C");
    break;
  default:
    console.log("F");
}
Answer

Output: "F"

Explanation:

  • score = "85" (string)
  • "85" >= 90false
  • "85" >= 80true, but true !== true in switch context
  • All comparisons return boolean, but switch looks for exact match with true
  • No case executes, default triggers

Correct approach:

const score = Number("85"); // Convert to number
 
if (score >= 90) {
  console.log("A");
} else if (score >= 80) {
  console.log("B");
} else if (score >= 70) {
  console.log("C");
} else {
  console.log("F");
}

Task 4: Fix the function

// ❌ Problematic function
function getDiscountByCategory(category, isPremium) {
  switch (category) {
    case "electronics":
      if (isPremium) {
        return 0.15;
      }
      return 0.10;
    case "clothing":
      if (isPremium) {
        return 0.20;
      }
      return 0.15;
    case "books":
      return 0.05;
  }
}
 
console.log(getDiscountByCategory("electronics", true));  // ?
console.log(getDiscountByCategory("unknown", false));     // ?
Answer

Problems:

  1. No default case
  2. Function can return undefined
  3. No validation of input data

Fixed version:

function getDiscountByCategory(category, isPremium = false) {
  // Input validation
  if (typeof category !== "string") {
    throw new Error("Category must be a string");
  }
  
  if (typeof isPremium !== "boolean") {
    throw new Error("isPremium must be boolean");
  }
  
  const normalizedCategory = category.toLowerCase();
  
  switch (normalizedCategory) {
    case "electronics":
      return isPremium ? 0.15 : 0.10;
    
    case "clothing":
      return isPremium ? 0.20 : 0.15;
    
    case "books":
      return 0.05; // Same discount for all
    
    default:
      return 0; // No discount for unknown categories
  }
}
 
// Alternative approach with object
const DISCOUNTS = {
  electronics: { regular: 0.10, premium: 0.15 },
  clothing: { regular: 0.15, premium: 0.20 },
  books: { regular: 0.05, premium: 0.05 }
};
 
function getDiscountByCategory2(category, isPremium = false) {
  const categoryData = DISCOUNTS[category.toLowerCase()];
  if (!categoryData) {
    return 0;
  }
  return isPremium ? categoryData.premium : categoryData.regular;
}

When to use switch vs if-else

Use switch when:

// ✅ Many specific values
function getHttpStatusText(code) {
  switch (code) {
    case 200: return "OK";
    case 201: return "Created";
    case 400: return "Bad Request";
    case 401: return "Unauthorized";
    case 403: return "Forbidden";
    case 404: return "Not Found";
    case 500: return "Internal Server Error";
    default: return "Unknown Status";
  }
}
 
// ✅ Grouping similar cases
function isWeekend(day) {
  switch (day.toLowerCase()) {
    case "saturday":
    case "sunday":
      return true;
    default:
      return false;
  }
}
 
// ✅ State machine
function processState(currentState, action) {
  switch (currentState) {
    case "idle":
      switch (action) {
        case "start": return "running";
        case "reset": return "idle";
        default: return currentState;
      }
    case "running":
      switch (action) {
        case "pause": return "paused";
        case "stop": return "stopped";
        default: return currentState;
      }
    // ... other states
  }
}

Use if-else when:

// ✅ Value ranges
function getGrade(score) {
  if (score >= 90) {
    return "A";
  } else if (score >= 80) {
    return "B";
  } else if (score >= 70) {
    return "C";
  } else if (score >= 60) {
    return "D";
  } else {
    return "F";
  }
}
 
// ✅ Complex conditions
function canAccessResource(user, resource) {
  if (user.isAdmin) {
    return true;
  } else if (user.role === "moderator" && resource.type === "public") {
    return true;
  } else if (user.id === resource.ownerId) {
    return true;
  } else {
    return false;
  }
}
 
// ✅ Conditions with logical operators
function shouldShowNotification(user, notification) {
  if (user.preferences.notifications && 
      !user.isDoNotDisturb && 
      notification.priority === "high") {
    return true;
  }
  return false;
}

Modern Alternatives

1. Object as lookup table

// Instead of switch
function getAnimalSound(animal) {
  switch (animal) {
    case "dog": return "Woof!";
    case "cat": return "Meow!";
    case "cow": return "Moo!";
    case "pig": return "Oink!";
    default: return "Unknown sound";
  }
}
 
// ✅ Modern approach
const ANIMAL_SOUNDS = {
  dog: "Woof!",
  cat: "Meow!",
  cow: "Moo!",
  pig: "Oink!"
};
 
function getAnimalSound(animal) {
  return ANIMAL_SOUNDS[animal] ?? "Unknown sound";
}

2. Map for complex cases

// ✅ Map with functions
const ACTION_HANDLERS = new Map([
  ["CREATE", (data) => createItem(data)],
  ["UPDATE", (data) => updateItem(data)],
  ["DELETE", (data) => deleteItem(data)],
  ["READ", (data) => readItem(data)]
]);
 
function handleAction(action, data) {
  const handler = ACTION_HANDLERS.get(action.toUpperCase());
  if (handler) {
    return handler(data);
  }
  throw new Error(`Unknown action: ${action}`);
}

3. Polymorphism (classes)

// ✅ Object-oriented approach
class Shape {
  calculateArea() {
    throw new Error("Method must be implemented");
  }
}
 
class Circle extends Shape {
  constructor(radius) {
    super();
    this.radius = radius;
  }
  
  calculateArea() {
    return Math.PI * this.radius ** 2;
  }
}
 
class Rectangle extends Shape {
  constructor(width, height) {
    super();
    this.width = width;
    this.height = height;
  }
  
  calculateArea() {
    return this.width * this.height;
  }
}
 
// Usage
function getArea(shape) {
  return shape.calculateArea(); // Polymorphism instead of switch
}

Best Practices

1. Always use break

// ✅ Good: explicit break
switch (action) {
  case "save":
    saveData();
    break;
  case "load":
    loadData();
    break;
  default:
    showError();
    break; // Even in default for consistency
}
 
// ❌ Bad: forgotten break
switch (action) {
  case "save":
    saveData();
    // Forgot break!
  case "load":
    loadData(); // Will execute for "save" too!
    break;
}

2. Use default

// ✅ Good: handle all cases
function processUserRole(role) {
  switch (role) {
    case "admin":
      return { permissions: ["read", "write", "delete"] };
    case "user":
      return { permissions: ["read"] };
    case "guest":
      return { permissions: [] };
    default:
      throw new Error(`Unknown role: ${role}`);
  }
}
 
// ❌ Bad: no default
function processUserRoleBad(role) {
  switch (role) {
    case "admin":
      return { permissions: ["read", "write", "delete"] };
    case "user":
      return { permissions: ["read"] };
  }
  // What if role = "guest"? Returns undefined!
}
// ✅ Good: logical grouping
function getBusinessHours(day) {
  switch (day.toLowerCase()) {
    case "monday":
    case "tuesday":
    case "wednesday":
    case "thursday":
    case "friday":
      return "9:00 - 18:00";
    
    case "saturday":
      return "10:00 - 16:00";
    
    case "sunday":
      return "Closed";
    
    default:
      return "Unknown day";
  }
}

4. Avoid complex logic in case

// ❌ Bad: complex logic in case
switch (userType) {
  case "premium":
    if (user.subscriptionActive && user.paymentValid) {
      if (user.lastLogin > Date.now() - 30 * 24 * 60 * 60 * 1000) {
        return getPremiumFeatures();
      } else {
        return getBasicFeatures();
      }
    }
    break;
  // ...
}
 
// ✅ Good: extract logic to functions
function isPremiumActive(user) {
  return user.subscriptionActive && 
         user.paymentValid && 
         user.lastLogin > Date.now() - 30 * 24 * 60 * 60 * 1000;
}
 
switch (userType) {
  case "premium":
    return isPremiumActive(user) ? getPremiumFeatures() : getBasicFeatures();
  case "basic":
    return getBasicFeatures();
  default:
    return getGuestFeatures();
}

5. Use ESLint rules

// .eslintrc.json
{
  "rules": {
    "default-case": "error",           // Requires default
    "no-fallthrough": "error",        // Warns about fall-through
    "no-case-declarations": "error"   // Prohibits declarations in case
  }
}

Common Mistakes

1. Forgotten break

// ❌ Error
function getPrice(category) {
  let price = 0;
  
  switch (category) {
    case "basic":
      price = 10;
      // Forgot break!
    case "premium":
      price = 20;
      break;
    case "enterprise":
      price = 50;
      break;
  }
  
  return price;
}
 
console.log(getPrice("basic")); // 20 instead of 10!

2. Variable declarations in case

// ❌ Error: variables "hoist"
switch (type) {
  case "A":
    let result = "Type A"; // Error!
    break;
  case "B":
    let result = "Type B"; // Error: redeclaration!
    break;
}
 
// ✅ Correct: use blocks
switch (type) {
  case "A": {
    let result = "Type A";
    console.log(result);
    break;
  }
  case "B": {
    let result = "Type B";
    console.log(result);
    break;
  }
}

3. Comparison with type coercion

// ❌ Error: expecting type coercion
const userInput = "1";
 
switch (userInput) {
  case 1:  // Won't work! "1" !== 1
    console.log("One");
    break;
}
 
// ✅ Correct: convert type beforehand
const userInputNumber = Number(userInput);
 
switch (userInputNumber) {
  case 1:
    console.log("One");
    break;
}

4. Using switch for ranges

// ❌ Bad: switch not suitable for ranges
switch (true) {
  case age >= 18 && age < 65:
    return "Adult";
  case age >= 65:
    return "Senior";
  default:
    return "Child";
}
 
// ✅ Good: use if-else
if (age >= 65) {
  return "Senior";
} else if (age >= 18) {
  return "Adult";
} else {
  return "Child";
}

Performance

Switch vs If-Else

// For many conditions switch can be&nbsp;faster
function getColorHex(color) {
  // Switch: O(1) in&nbsp;best case (jump table)
  switch (color) {
    case "red": return "#FF0000";
    case "green": return "#00FF00";
    case "blue": return "#0000FF";
    case "yellow": return "#FFFF00";
    case "purple": return "#800080";
    case "orange": return "#FFA500";
    case "pink": return "#FFC0CB";
    case "brown": return "#A52A2A";
    default: return "#000000";
  }
}
 
// If-else: O(n) in&nbsp;worst case
function getColorHexIfElse(color) {
  if (color === "red") return "#FF0000";
  else if (color === "green") return "#00FF00";
  else if (color === "blue") return "#0000FF";
  else if (color === "yellow") return "#FFFF00";
  else if (color === "purple") return "#800080";
  else if (color === "orange") return "#FFA500";
  else if (color === "pink") return "#FFC0CB";
  else if (color === "brown") return "#A52A2A";
  else return "#000000";
}
 
// Object: O(1) always
const COLOR_MAP = {
  red: "#FF0000",
  green: "#00FF00",
  blue: "#0000FF",
  yellow: "#FFFF00",
  purple: "#800080",
  orange: "#FFA500",
  pink: "#FFC0CB",
  brown: "#A52A2A"
};
 
function getColorHexObject(color) {
  return COLOR_MAP[color] ?? "#000000";
}

Conclusion

Key points about switch:

  1. Strict comparison — uses ===, doesn’t convert types
  2. Fall-through — execution continues until break
  3. Mandatory break — without it code “falls through” to next case
  4. Default case — always add to handle unexpected values
  5. Grouping — use to combine similar cases

When to use:

  • ✅ Many specific values to compare
  • ✅ Grouping similar cases
  • ✅ State machines
  • ❌ Value ranges (use if-else)
  • ❌ Complex conditions (use if-else)

Modern alternatives:

  • Objects as lookup tables
  • Map for complex cases
  • Polymorphism for OOP approach

Remember: Switch is a powerful tool, but not a universal solution. Choose the right tool for each task!


Want more articles for interview preparation? Subscribe to EasyAdvice, bookmark the site and level up every day 💪