Оператор switch
выполняет строгое сравнение (===
) между выражением и значениями в case
. Не приводит типы и использует fall-through механизм:
const value = "5";
switch (value) {
case 5: // false ("5" !== 5)
console.log("Число");
break;
case "5": // true ("5" === "5")
console.log("Строка");
break;
default:
console.log("Другое");
}
// Выведет: "Строка"
Ключевые особенности: Строгое сравнение, обязательный break
, выполнение до первого break
.
switch (выражение) {
case значение1:
// код для значения1
break;
case значение2:
// код для значения2
break;
default:
// код по умолчанию
}
const userInput = "1";
switch (userInput) {
case 1: // false ("1" !== 1)
console.log("Число один");
break;
case "1": // true ("1" === "1")
console.log("Строка один");
break;
case true: // false ("1" !== true)
console.log("Булево");
break;
}
// Выведет: "Строка один"
// Switch использует строгое сравнение
const value = 0;
switch (value) {
case false: // false (0 !== false)
console.log("Ложь");
break;
case 0: // true (0 === 0)
console.log("Ноль");
break;
}
// Выведет: "Ноль"
// Эквивалентный if-else
if (value === false) {
console.log("Ложь");
} else if (value === 0) {
console.log("Ноль");
}
Значение | switch case | if (==) | if (===) | Объяснение |
---|---|---|---|---|
"5" vs 5 | false | true | false | Switch использует строгое сравнение |
0 vs false | false | true | false | Нет приведения типов в switch |
"" vs 0 | false | true | false | Switch не приводит типы |
null vs undefined | false | true | false | Строгое сравнение в switch |
1 vs true | false | true | false | Разные типы для switch |
"hello" vs "hello" | true | true | true | Одинаковые строки |
NaN vs NaN | false | false | false | NaN не равен самому себе |
Fall-through — выполнение кода продолжается до первого break
или конца блока:
const day = "понедельник";
switch (day) {
case "понедельник":
console.log("Начало недели");
// НЕТ break! Продолжаем выполнение
case "вторник":
console.log("Рабочий день");
break;
case "суббота":
case "воскресенье":
console.log("Выходной");
break;
}
// Выведет:
// "Начало недели"
// "Рабочий день"
// Группировка случаев
function getSeasonByMonth(month) {
switch (month) {
case "декабрь":
case "январь":
case "февраль":
return "Зима";
case "март":
case "апрель":
case "май":
return "Весна";
case "июнь":
case "июль":
case "август":
return "Лето";
case "сентябрь":
case "октябрь":
case "ноябрь":
return "Осень";
default:
return "Неизвестный месяц";
}
}
console.log(getSeasonByMonth("январь")); // "Зима"
⚠️ Внимание! Забытый break
может привести к неожиданному поведению:
// ❌ Ошибка: забыли break
function processGrade(grade) {
switch (grade) {
case "A":
console.log("Отлично!");
// Забыли break!
case "B":
console.log("Хорошо!");
break;
case "C":
console.log("Удовлетворительно");
break;
default:
console.log("Нужно подтянуть");
}
}
processGrade("A");
// Выведет:
// "Отлично!"
// "Хорошо!" (нежелательно!)
function handleHttpStatus(status) {
switch (status) {
case 200:
case 201:
case 204:
return "Успех";
case 400:
return "Неверный запрос";
case 401:
return "Не авторизован";
case 403:
return "Доступ запрещен";
case 404:
return "Не найдено";
case 500:
case 502:
case 503:
return "Ошибка сервера";
default:
return `Неизвестный статус: ${status}`;
}
}
console.log(handleHttpStatus(200)); // "Успех"
console.log(handleHttpStatus("200")); // "Неизвестный статус: 200"
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("Деление на ноль");
}
return a / b;
case "**":
case "^":
return Math.pow(a, b);
default:
throw new Error(`Неизвестный оператор: ${operator}`);
}
}
console.log(calculate(5, "+", 3)); // 8
console.log(calculate(10, "/", 2)); // 5
function validateInput(value, expectedType) {
const actualType = typeof value;
switch (expectedType) {
case "string":
if (actualType === "string" && value.length > 0) {
return { valid: true, message: "Валидная строка" };
}
return { valid: false, message: "Ожидается непустая строка" };
case "number":
if (actualType === "number" && !isNaN(value)) {
return { valid: true, message: "Валидное число" };
}
return { valid: false, message: "Ожидается число" };
case "boolean":
if (actualType === "boolean") {
return { valid: true, message: "Валидный boolean" };
}
return { valid: false, message: "Ожидается boolean" };
case "array":
if (Array.isArray(value)) {
return { valid: true, message: "Валидный массив" };
}
return { valid: false, message: "Ожидается массив" };
default:
return { valid: false, message: `Неизвестный тип: ${expectedType}` };
}
}
console.log(validateInput("hello", "string")); // { valid: true, ... }
console.log(validateInput(42, "string")); // { valid: false, ... }
const value = 1;
switch (value) {
case "1":
console.log("Строка");
break;
case 1:
console.log("Число");
case true:
console.log("Булево");
break;
default:
console.log("Другое");
}
Объяснение:
value = 1
строго равно case 1
, поэтому выполняется этот блокbreak
после case 1
, поэтому выполнение продолжаетсяcase true
(fall-through)break
останавливает выполнениеfunction getDayType(day) {
switch (day) {
case "понедельник":
case "вторник":
case "среда":
case "четверг":
case "пятница":
return "Рабочий день";
case "суббота":
case "воскресенье":
return "Выходной";
}
}
console.log(getDayType("понедельник")); // ?
console.log(getDayType("ПОНЕДЕЛЬНИК")); // ?
console.log(getDayType("пн")); // ?
Результат:
getDayType("понедельник")
→ "Рабочий день"
getDayType("ПОНЕДЕЛЬНИК")
→ undefined
getDayType("пн")
→ undefined
Проблемы:
default
случаяИсправленная версия:
function getDayType(day) {
const normalizedDay = day.toLowerCase();
switch (normalizedDay) {
case "понедельник":
case "пн":
case "вторник":
case "вт":
case "среда":
case "ср":
case "четверг":
case "чт":
case "пятница":
case "пт":
return "Рабочий день";
case "суббота":
case "сб":
case "воскресенье":
case "вс":
return "Выходной";
default:
return "Неизвестный день";
}
}
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");
}
Объяснение:
score = "85"
(строка)"85" >= 90
→ false
"85" >= 80
→ true
, но true !== true
в контексте switchtrue
default
Правильный способ:
const score = Number("85"); // Приводим к числу
if (score >= 90) {
console.log("A");
} else if (score >= 80) {
console.log("B");
} else if (score >= 70) {
console.log("C");
} else {
console.log("F");
}
// ❌ Проблемная функция
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)); // ?
Проблемы:
default
случаяundefined
Исправленная версия:
function getDiscountByCategory(category, isPremium = false) {
// Валидация входных данных
if (typeof category !== "string") {
throw new Error("Категория должна быть строкой");
}
if (typeof isPremium !== "boolean") {
throw new Error("isPremium должен быть 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; // Одинаковая скидка для всех
default:
return 0; // Нет скидки для неизвестных категорий
}
}
// Альтернативный подход с объектом
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;
}
// ✅ Много конкретных значений
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";
}
}
// ✅ Группировка похожих случаев
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;
}
// ... другие состояния
}
}
// ✅ Диапазоны значений
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";
}
}
// ✅ Сложные условия
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;
}
}
// ✅ Условия с логическими операторами
function shouldShowNotification(user, notification) {
if (user.preferences.notifications &&
!user.isDoNotDisturb &&
notification.priority === "high") {
return true;
}
return false;
}
// Вместо 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";
}
}
// ✅ Современный подход
const ANIMAL_SOUNDS = {
dog: "Woof!",
cat: "Meow!",
cow: "Moo!",
pig: "Oink!"
};
function getAnimalSound(animal) {
return ANIMAL_SOUNDS[animal] ?? "Unknown sound";
}
// ✅ Map с функциями
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}`);
}
// ✅ Объектно-ориентированный подход
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;
}
}
// Использование
function getArea(shape) {
return shape.calculateArea(); // Полиморфизм вместо switch
}
// ✅ Хорошо: явный break
switch (action) {
case "save":
saveData();
break;
case "load":
loadData();
break;
default:
showError();
break; // Даже в default для консистентности
}
// ❌ Плохо: забытый break
switch (action) {
case "save":
saveData();
// Забыли break!
case "load":
loadData(); // Выполнится и для "save"!
break;
}
// ✅ Хорошо: обрабатываем все случаи
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}`);
}
}
// ❌ Плохо: нет default
function processUserRoleBad(role) {
switch (role) {
case "admin":
return { permissions: ["read", "write", "delete"] };
case "user":
return { permissions: ["read"] };
}
// Что если role = "guest"? Вернется undefined!
}
// ✅ Хорошо: логическая группировка
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 "Закрыто";
default:
return "Неизвестный день";
}
}
// ❌ Плохо: сложная логика в 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;
// ...
}
// ✅ Хорошо: выносим логику в функции
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();
}
// .eslintrc.json
{
"rules": {
"default-case": "error", // Требует default
"no-fallthrough": "error", // Предупреждает о fall-through
"no-case-declarations": "error" // Запрещает объявления в case
}
}
// ❌ Ошибка
function getPrice(category) {
let price = 0;
switch (category) {
case "basic":
price = 10;
// Забыли break!
case "premium":
price = 20;
break;
case "enterprise":
price = 50;
break;
}
return price;
}
console.log(getPrice("basic")); // 20 вместо 10!
// ❌ Ошибка: переменные "всплывают"
switch (type) {
case "A":
let result = "Type A"; // Ошибка!
break;
case "B":
let result = "Type B"; // Ошибка: повторное объявление!
break;
}
// ✅ Правильно: используйте блоки
switch (type) {
case "A": {
let result = "Type A";
console.log(result);
break;
}
case "B": {
let result = "Type B";
console.log(result);
break;
}
}
// ❌ Ошибка: ожидание приведения типов
const userInput = "1";
switch (userInput) {
case 1: // Не сработает! "1" !== 1
console.log("Один");
break;
}
// ✅ Правильно: приводим тип заранее
const userInputNumber = Number(userInput);
switch (userInputNumber) {
case 1:
console.log("Один");
break;
}
// ❌ Плохо: switch не подходит для диапазонов
switch (true) {
case age >= 18 && age < 65:
return "Взрослый";
case age >= 65:
return "Пенсионер";
default:
return "Ребенок";
}
// ✅ Хорошо: используйте if-else
if (age >= 65) {
return "Пенсионер";
} else if (age >= 18) {
return "Взрослый";
} else {
return "Ребенок";
}
// Для многих условий switch может быть быстрее
function getColorHex(color) {
// Switch: O(1) в лучшем случае (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) в худшем случае
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";
}
// Объект: O(1) всегда
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";
}
Ключевые моменты о switch:
===
, не приводит типыbreak
Когда использовать:
Современные альтернативы:
Помните: Switch — мощный инструмент, но не универсальное решение. Выбирайте подходящий инструмент для каждой задачи!
Хотите больше статей для подготовки к собеседованиям? Подписывайтесь на EasyAdvice(@AleksandrEmolov_EasyAdvice), добавляйте сайт в закладки и прокачивайтесь каждый день 💪