Switch case в JavaScript: ветвление в алгоритме, break и default

Switch case в JavaScript: ветвление в алгоритме, break и default Полезное

Switch case в JavaScript — это оператор множественного ветвления: он один раз вычисляет выражение в скобках, сравнивает результат с метками case строгим сравнением === и начинает выполнять код с первой совпавшей метки. В алгоритме он заменяет цепочку if ... else if, когда одно значение сверяется с несколькими заранее известными вариантами.

Три части конструкции делают разную работу, и путать их не стоит. 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

Что здесь происходит по шагам:

  1. Выражение status вычисляется один раз.
  2. Результат по очереди сравнивается с метками сверху вниз, пока не найдется совпадение.
  3. С совпавшей метки начинается выполнение. Здесь return сразу завершает функцию, поэтому break не нужен.
  4. Значения "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.

OTUS Журнал
Скидка 10% до 10 ноября (поп-ап)
Бесплатные открытые уроки (поп-ап)