Гид по технологиям

Как упростить длинные if...else цепочки в JavaScript

4 min read JavaScript Обновлено 02 Apr 2026
Упрощение длинных if...else в JavaScript
Упрощение длинных if...else в JavaScript

13-дюймовый MacBook Pro с открытым кодом рядом с цветком

Условные операторы — основа JavaScript. Они позволяют выполнять код в зависимости от условия (true/false). Но длинные вложенные цепочки if…else быстро становятся трудными для понимания и сопровождения.

В этой статье показаны практические приёмы для рефакторинга таких цепочек: guard‑clauses (проверки‑охранники), множественные return, извлечение функций, а также альтернативы и рекомендации, когда эти приёмы не подойдут.

Проблема: сложные вложенные if…else

Рассмотрим исходный пример с вложенностью:

function canDrink(person) {  
  if(person?.age != null) {  
    if(person.age < 18) {  
      console.log("Still too young")  
    } else if(person.age < 21) {  
      console.log("Not in the US")  
    } else {  
      console.log("Allowed to drink")  
    }  
  } else {  
    console.log("You're not a person")  
  }  
}  
  
const person = {  
  age: 22  
}  
  
canDrink(person)

Логика простая: сначала проверяем наличие возраста, затем сравниваем возраст по порогам. Но вложенность затрудняет чтение: чтобы понять ветвление, нужно прокрутить и мысленно распаковать всё дерево условий.

Guard‑clauses — убираем верхнюю вложенность

Если верхняя проверка охватывает весь остальной код функции, лучше сделать проверку‑охранник и немедленно выйти из функции, когда условие не выполняется:

function canDrinkBetter(person) {  
  if(person?.age == null) return console.log("Вы не человек")     

  if(person.age < 18) {  
    console.log("Слишком молод")  
  } else if(person.age < 21) {  
    console.log("Младше 21 (не в США)")  
  } else {  
    console.log("Можно пить")  
  }  
}

Преимущество: верхняя ветвь вынесена, остальной код расположен «вровень», становится проще читать и тестировать.

Множественные return — ещё проще

Не бойтесь нескольких return в функции. Они помогают убрать else и упростить поток выполнения:

function canDrinkBetter(person) {  
  if(person?.age == null) return console.log("Вы не человек")     

  if(person.age < 18) {  
    console.log("Слишком молод")  
    return  
  }   

  if(person.age < 21) {  
    console.log("Младше 21 (не в США)")  
    return  
  }  

  console.log("Можно пить")   
}

Каждая ветка завершает функцию самостоятельно, поэтому нет нужды в else. Код читается сверху вниз как сценарий принятия решения.

Извлечь функцию — разделяем ответственность

Лучше выносить логику принятия решения в отдельную чистую функцию, которая возвращает результат. Это упрощает тесты и делает функции компактными:

function canDrinkResult(age) {  
  if(age < 18) return "Слишком молод"  
  if(age < 21) return "Младше 21 (не в США)"  
  return "Можно пить"  
}

function canDrinkBetter(person) {     
  if(person?.age == null) return console.log("Вы не человек")     

  let result = canDrinkResult(person.age)  
  console.log(result)  
}

Теперь задача определения результата полностью отделена от функции, которая отвечает за побочный эффект (логирование). Это соответствует принципу единственной ответственности (SRP).

Когда не стоит убирать else (контрпример)

  • Если после ветки нужно выполнить общий код очистки/освобождения ресурсов: в таких случаях часто удобнее иметь единый блок выполнения или использовать try/finally.
  • Когда функция должна возвращать единый объект состояния, а не сразу завершаться побочным действием: может быть удобен один return в конце.
  • Если код читается яснее с явно выраженным else (крайне редкие случаи) — не превращайте читаемость в догму.

Important: guard‑clauses полезны, но не заменяют правильную архитектуру и управление ресурсами.

Альтернативы и приёмы

  • Switch/case: подходит для дискретных значений, но хуже для диапазонов (возрастных интервалов).
switch (true) {
  case (age < 18):
    return "Слишком молод"
  case (age < 21):
    return "Младше 21"
  default:
    return "Можно пить"
}
  • Таблица соответствий (lookup): полезна для сопоставления конкретных значений или статусов.
  • Массив правил + find: полезно, если правил много и их хочется хранить декларативно.

Пример с правилами:

const rules = [
  { check: age => age < 18, result: "Слишком молод" },
  { check: age => age < 21, result: "Младше 21" },
  { check: () => true, result: "Можно пить" }
]

function canDrinkResult(age) {
  return rules.find(r => r.check(age)).result
}

Ментальные модели и эвристики

  • Принцип «раннего выхода»: обрабатывайте исключительные/редкие случаи в начале, затем основную логику без вложенности.
  • Каждый уровень вложенности увеличивает когнитивную нагрузку. Старайтесь не превышать 2–3 уровней вложенности.
  • Выносите условие в функцию с говорящим именем, если условие длинное или содержит бизнес‑логику.

Факто‑бокс: ключевые числа

  • 18 — типичная нижняя граница для «слишком молод» в примерах.
  • 21 — юридический возраст потребления в США (частый пример в обучающих материалах).

(Это примеры, не юридическая консультация.)

Решение в виде блок‑схемы (Mermaid)

flowchart TD
  A[Есть person.age?] -->|нет| B[Лог: Вы не человек] --> Z[Конец]
  A -->|да| C[age < 18?]
  C -->|да| D[Лог: Слишком молод] --> Z
  C -->|нет| E[age < 21?]
  E -->|да| F[Лог: Младше 21] --> Z
  E -->|нет| G[Лог: Можно пить] --> Z

Чек‑лист для ревью кода (роль: reviewer)

  • Понять ли логику без прокрутки вверх/вниз? Если нет — вынести в функцию.
  • Есть ли первичная проверка на некорректные входные данные (guard)?
  • Отсутствует ли лишняя вложенность else? Можно ли заменить её ранними return?
  • Можно ли заменить несколько похожих условий таблицей правил или конфигурацией?
  • Есть ли тесты на каждую ветку результата?

Краткая методология рефакторинга

  1. Найдите верхние условия, которые покрывают весь метод — превратите в guard‑clauses.
  2. Уберите else, заменив их ранними return там, где это уместно.
  3. Вынесите сложные условий в именованные функции (canDrinkResult, isMinor и т.д.).
  4. Если правил много — рассмотрите декларативный подход (rules array / lookup table).
  5. Добавьте юнит‑тесты для каждого правила.

Краткое резюме

Используйте guard‑clauses и вынос логики в отдельные функции, чтобы избавиться от глубокой вложенности и улучшить читаемость. Множественные return — не зло; они делают код последовательным и простым для понимания. В тех случаях, когда необходима единая точка очистки ресурсов или согласованная возвратная структура, применяйте соответствующие паттерны (try/finally, единый объект состояния).

Notes: эти приёмы повышают читаемость и тестируемость, но не заменяют здравый смысл и контекст проекта.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Запуск Командной строки от имени администратора
Windows

Запуск Командной строки от имени администратора

Отключить напоминания Facebook Memories и скрыть их
Социальные сети

Отключить напоминания Facebook Memories и скрыть их

Как управлять cookie в Chrome, Firefox и Edge
Приватность

Как управлять cookie в Chrome, Firefox и Edge

Как управлять расширениями в Chrome, Edge, Vivaldi
Браузеры

Как управлять расширениями в Chrome, Edge, Vivaldi

Добавить пользовательские эмодзи в Discord
Discord

Добавить пользовательские эмодзи в Discord

Вентилируемая подставка для ноутбука — 3 DIY-плана
DIY

Вентилируемая подставка для ноутбука — 3 DIY-плана