Switch case в JavaScript — это оператор множественного ветвления: он один раз вычисляет выражение в скобках, сравнивает результат с метками case строгим сравнением === и начинает выполнять код с первой совпавшей метки. В алгоритме он заменяет цепочку if ... else if, когда одно значение сверяется с несколькими заранее известными вариантами.
Содержание
- Минимальный рабочий пример switch case
- Break и проваливание: главная ошибка в switch
- Группировка case: когда проваливание полезно
- Строгое сравнение: почему case не срабатывает
- Область видимости внутри case
- Switch, if/else или объект-словарь
- Если switch работает не так, как ожидалось
- Выводы
- Где применяется / связь с практикой
- FAQ
Три части конструкции делают разную работу, и путать их не стоит. case — это метка входа, а не отдельный блок. break — выход из всего switch. default — метка на случай, когда ни одна case не совпала. Примеры ниже проверены в Node.js 24.21.0 30 сентября 2026 года; в браузере они работают так же, кроме текста одной синтаксической ошибки, о чем сказано отдельно.
Минимальный рабочий пример switch case
Функция переводит код статуса заказа в текст для пользователя. Сохраните код в файл status.js и запустите командой node status.js.
function deliveryText(status) {
switch (status) {
case "new":
return "Заказ принят";
case "paid":
return "Заказ оплачен, собираем";
case "sent":
return "Заказ в пути";
default:
return "Неизвестный статус: " + status;
}
}
console.log(deliveryText("paid"));
console.log(deliveryText("sent"));
console.log(deliveryText("lost"));
В консоли появятся три строки:
Заказ оплачен, собираем
Заказ в пути
Неизвестный статус: lost
Что здесь происходит по шагам:
- Выражение
statusвычисляется один раз. - Результат по очереди сравнивается с метками сверху вниз, пока не найдется совпадение.
- С совпавшей метки начинается выполнение. Здесь
returnсразу завершает функцию, поэтомуbreakне нужен. - Значения
"lost"среди меток нет, поэтому управление переходит наdefault.
default необязателен. Без него при отсутствии совпадений switch просто ничего не выполнит, а функция из примера вернула бы undefined. Поэтому ветку для неожиданного значения лучше писать явно.
Break и проваливание: главная ошибка в switch
Когда внутри case нет return, выйти из switch нужно оператором break. Если его пропустить, выполнение не остановится на следующей метке, а пойдет дальше по коду. Это называют проваливанием (fall-through).
Неверный вариант — расчет скидки по уровню клиента:
function discount(level) {
let rate = 0;
switch (level) {
case "diamond":
rate = 0.2;
case "gold":
rate = 0.1;
default:
rate = 0;
}
return rate;
}
console.log(discount("diamond"));
console.log(discount("gold"));
Фактический результат — оба клиента остались без скидки:
0
0
Для "diamond" переменная получила 0.2, затем код провалился в "gold" и записал 0.1, затем в default и записал 0. Ошибки в консоли нет, программа молча считает неверно. Исправление — break в конце каждой ветки:
function discount(level) {
let rate;
switch (level) {
case "diamond":
rate = 0.2;
break;
case "gold":
rate = 0.1;
break;
default:
rate = 0;
}
return rate;
}
console.log(discount("diamond"));
console.log(discount("gold"));
console.log(discount("silver"));
0.2
0.1
0
Пропущенный break не создает бесконечный цикл: switch не цикл, он выполняется один раз. Последствие другое — лишние ветки и неверный результат.
У break есть граница действия: внутри switch он выходит только из switch. Если switch стоит в теле цикла for или while, цикл продолжит работу.
Группировка case: когда проваливание полезно
Проваливание применяют намеренно, когда несколько значений ведут к одному действию. Метки ставят подряд, без кода между ними.
function dayType(day) {
switch (day) {
case "sat":
case "sun":
return "выходной";
case "mon":
case "tue":
case "wed":
case "thu":
case "fri":
return "будний";
default:
return "неизвестный день";
}
}
console.log(dayType("sun"));
console.log(dayType("wed"));
console.log(dayType("Sun"));
выходной
будний
неизвестный день
Пустые метки подряд читаются однозначно. Если же ветка выполняет код и затем намеренно проваливается в следующую, это стоит подписать комментарием вроде // проваливаемся дальше, иначе следующий читатель примет это за забытый break.
Строгое сравнение: почему case не срабатывает
Сравнение с метками идет по правилам ===, то есть без приведения типов. Строка "sun" не равна "Sun" (в примере выше), а строка "2" не равна числу 2. Это частая причина, по которой switch уходит в default: значение из поля формы или из адресной строки приходит строкой.
function roomName(code) {
switch (code) {
case 1:
return "переговорная";
case 2:
return "кухня";
default:
return "нет такой комнаты";
}
}
console.log(roomName(2));
console.log(roomName("2"));
console.log(roomName(Number("2")));
кухня
нет такой комнаты
кухня
Решение — привести значение к нужному типу до switch, как в третьем вызове. Еще одно следствие строгого сравнения: метка case NaN не сработает никогда, потому что NaN === NaN дает false. Объекты и массивы сравниваются по ссылке, поэтому case [] тоже не совпадет с другим пустым массивом.
Область видимости внутри case
Весь switch — это один блок с общей областью видимости для let и const. Метки case ее не делят, поэтому одно имя нельзя объявить в двух ветках.
function describe(shape) {
switch (shape) {
case "circle":
let label = "круг";
return label;
case "square":
let label = "квадрат";
return label;
}
}
Файл не запустится вообще. Node.js 24 сообщает об ошибке еще при разборе кода:
SyntaxError: Identifier 'label' has already been declared
Формулировка относится к движку V8 (Node.js, Chrome); в Firefox и Safari текст сообщения другой, но ошибка та же. Исправление — фигурные скобки вокруг тела ветки, они создают отдельный блок:
function describe(shape) {
switch (shape) {
case "circle": {
const label = "круг";
return label;
}
case "square": {
const label = "квадрат";
return label;
}
default:
return "неизвестная фигура";
}
}
console.log(describe("square"));
console.log(describe("star"));
квадрат
неизвестная фигура
Switch, if/else или объект-словарь
switch сверяет одно значение с набором констант. Для диапазонов и составных условий есть прием switch (true), где в метках стоят условия. Он рабочий, но обычная цепочка if читается проще: условие видно сразу, без обходной записи. Порядок проверок важен в обоих вариантах — срабатывает первое истинное условие.
function grade(score) {
if (typeof score !== "number" || !Number.isFinite(score)) {
return "некорректный балл";
}
if (score < 0 || score > 100) {
return "балл вне шкалы 0-100";
}
if (score >= 90) return "отлично";
if (score >= 70) return "хорошо";
if (score >= 50) return "зачет";
return "пересдача";
}
console.log(grade(95));
console.log(grade(70));
console.log(grade("abc"));
console.log(grade(1000));
отлично
хорошо
некорректный балл
балл вне шкалы 0-100
Первая проверка здесь не украшение: без нее строка "abc" не прошла бы ни одно сравнение и получила бы оценку «пересдача». Вторая проверка отсекает числа вне шкалы: без нее 1000 баллов дали бы «отлично».
Когда ветки только возвращают значение по ключу, switch заменяют объектом-словарем. У него есть ловушка: обычный объект наследует свойства вроде toString, и простое обращение по ключу их найдет.
const texts = {
new: "Заказ принят",
paid: "Заказ оплачен, собираем",
sent: "Заказ в пути",
};
function unsafeText(status) {
return texts[status] || "Неизвестный статус";
}
function safeText(status) {
return Object.hasOwn(texts, status) ? texts[status] : "Неизвестный статус";
}
console.log(safeText("paid"));
console.log(typeof unsafeText("toString"));
console.log(safeText("toString"));
Заказ оплачен, собираем
function
Неизвестный статус
Вариант без проверки вернул унаследованную функцию вместо текста. Object.hasOwn проверяет только собственные ключи объекта; другой надежный вариант — коллекция Map.
| Задача | Что взять | Почему |
|---|---|---|
| Одно значение против 3 и более констант, в ветках разные действия | switch |
Варианты видны списком, есть default |
| Диапазоны, сравнения, условия по разным переменным | if ... else if |
Условия любые и записаны прямо, проверяются сверху вниз |
| Два исхода, нужно значение | тернарный оператор ? : |
Короткая запись в одном выражении |
| Ключ -> значение без логики в ветках | объект с Object.hasOwn или Map |
Данные отделены от кода, легко дополнять |
Таблица — ориентир, а не норма языка: одну и ту же задачу можно решить любым способом. Скорость выполнения при выборе обычно не аргумент, разницу имеет смысл измерять только на реально горячем участке кода.
Если switch работает не так, как ожидалось
- Выполняется несколько веток подряд. Пропущен
breakилиreturnв конце ветки. - Всегда срабатывает default. Проверьте тип и регистр значения:
console.log(typeof value, value)передswitch. - SyntaxError про уже объявленный идентификатор. Одно имя объявлено через
letилиconstв двух ветках — оберните тела веток в фигурные скобки. - Цикл не останавливается после break.
breakвышел изswitch, а не из цикла. Вынеситеswitchв функцию и используйтеreturn.
Выводы
switchвычисляет выражение один раз и сравнивает его с меткамиcaseчерез===, без приведения типов.case— точка входа, а не блок: безbreakилиreturnвыполнение проваливается в следующие ветки, и ошибки при этом нет.- Метки подряд без кода группируют значения с общим действием;
defaultловит все остальное и необязателен, но полезен. - У всего
switchодна область видимости: дляletиconstв ветках нужны фигурные скобки. - Для диапазонов удобнее
if ... else if, для таблицы «ключ — значение» — объект сObject.hasOwnилиMap.
Где применяется / связь с практикой
В реальном коде switch встречается там, где есть конечный набор состояний: обработка нажатой клавиши по event.key, маршрутизация по типу сообщения, статусы заказа или задачи, функции-редьюсеры, которые меняют состояние интерфейса по типу действия. Во всех этих случаях работают те же правила: строгое сравнение, явный default и выход из каждой ветки.
Освойте тему на практике
Ветвления, функции, работа с объектами и отладка в браузере и Node.js входят в программу курса «JavaScript-разработчик. Базовый уровень». Посмотреть формат занятий до записи можно на открытых уроках Otus.
FAQ
Может ли default стоять не последним?
Да, позиция default на выбор ветки не влияет: он сработает, только если не совпала ни одна метка. Но если он стоит не в конце и без break, выполнение провалится из него в следующие ветки, поэтому его принято писать последним.
Вычисляются ли все выражения в case?
Нет. Метки проверяются сверху вниз, и после первого совпадения остальные не вычисляются. В метке может стоять не только константа, но и любое выражение, например вызов функции.
Что будет, если две метки case одинаковые?
Синтаксической ошибки не будет, сработает первая по порядку, а вторая станет недостижимой. Такие дубли ловит линтер, например правило no-duplicate-case в ESLint.


