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

Условные операторы — основа 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?
- Можно ли заменить несколько похожих условий таблицей правил или конфигурацией?
- Есть ли тесты на каждую ветку результата?
Краткая методология рефакторинга
- Найдите верхние условия, которые покрывают весь метод — превратите в guard‑clauses.
- Уберите else, заменив их ранними return там, где это уместно.
- Вынесите сложные условий в именованные функции (canDrinkResult, isMinor и т.д.).
- Если правил много — рассмотрите декларативный подход (rules array / lookup table).
- Добавьте юнит‑тесты для каждого правила.
Краткое резюме
Используйте guard‑clauses и вынос логики в отдельные функции, чтобы избавиться от глубокой вложенности и улучшить читаемость. Множественные return — не зло; они делают код последовательным и простым для понимания. В тех случаях, когда необходима единая точка очистки ресурсов или согласованная возвратная структура, применяйте соответствующие паттерны (try/finally, единый объект состояния).
Notes: эти приёмы повышают читаемость и тестируемость, но не заменяют здравый смысл и контекст проекта.
Похожие материалы
Запуск Командной строки от имени администратора
Отключить напоминания Facebook Memories и скрыть их
Как управлять cookie в Chrome, Firefox и Edge
Как управлять расширениями в Chrome, Edge, Vivaldi
Добавить пользовательские эмодзи в Discord