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

Чистые функции в JavaScript: понятие, преимущества и практическое руководство

7 min read JavaScript Обновлено 04 Jan 2026
Чистые функции в JavaScript — руководство
Чистые функции в JavaScript — руководство

Большой логотип JavaScript на синем фоне

Чистые функции — это функции, которые не производят побочных эффектов и при одинаковых входных параметрах всегда возвращают одинаковый результат.

Их применяют, чтобы код был аккуратным, поддерживаемым и легко тестируемым. Чистые функции предсказуемы и не изменяют внешнее состояние. Они проще для отладки и полезны при разработке сложных систем. Ниже разберём, как распознать чистую функцию в JavaScript, какие у неё характеристики и какие преимущества она даёт.

Что такое чистая функция

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

Ключевые моменты:

  • Входы → Выход без побочных эффектов.
  • Не зависит от внешнего состояния (глобальных переменных, времени, случайности и т. п.).
  • Не изменяет переданные объекты (не мутирует аргументы).

Характеристики чистой функции

Постоянный результат

Чистая функция всегда возвращает одно и то же значение для одних и тех же аргументов.

Пример:

function multiply(a, b) {  
  return a * b;  
}  

Функция multiply выше всегда вернёт произведение двух аргументов. Повторный вызов с теми же аргументами даст тот же результат:

multiply(2, 3);  // returns 6  
multiply(2, 3);  // returns 6  
multiply(2, 3);  // returns 6  

Контрпример с непредсказуемым поведением:

function multiplyRandomNumber(num) {  
  return num * Math.floor(Math.random() * 10);  
}  
  
multiplyRandomNumber(5);  // Unpredictable results  
multiplyRandomNumber(5);  // Unpredictable results  
multiplyRandomNumber(5);  // Unpredictable results  

multiplyRandomNumber зависит от Math.random(), поэтому результат меняется — это императивный признак нечистой функции.

Отсутствие побочных эффектов

Чистая функция не должна изменять состояние вне своего лексического окружения. Побочный эффект — любое действие, которое наблюдается за пределами функции: изменение глобальной переменной, запись в консоль, сетевой запрос, модификация DOM и т. п.

Нечистый пример:

let count = 0;  
  
function increment() {  
  count++;  
  console.log(count);  
}  
  
increment();  // Logs 1  
increment();  // Logs 2  
increment();  // Logs 3  

Функция increment меняет внешний count и выводит в консоль — она нечистая.

Приведём чистую версию:

function increment(count) {  
  return count + 1;  
}  
  
increment(1);  // returns 2  
increment(1);  // returns 2  
increment(1);  // returns 2  

Эта версия не меняет внешний state и при одинаковом входе возвращает одинаковое значение.

Другие правила

  • Функция не должна модифицировать свои аргументы. Если нужно изменить структуру — создайте копию и изменяйте её.
  • Функция должна возвращать значение. Если у неё нет return и нет побочных эффектов, она бесполезна.
  • Не полагайтесь на внешнее состояние. Все необходимые данные должны приходить через параметры.

Важно: «чистота» — это свойство кода на уровне функциональных блоков. В реальном приложении часть функций будет нечистой (ввод/вывод, работа с сетью, логирование). Хорошая архитектура отделяет чистую бизнес‑логику от нечистой инфраструктуры.

Преимущества чистых функций

Тестируемость

Чистые функции легко тестировать: вход → ожидаемый выход. Нет необходимости поднимать сложный контекст или мокать внешнее состояние.

Пример: для multiply можно писать простые модульные тесты без подготовки окружения.

Мемоизация

Поскольку чистая функция при одинаковом входе даёт одинаковый выход и не имеет побочных эффектов, её легко кешировать. Мемоизация подходит для дорогих вычислений и повторяющихся запросов с теми же данными.

Подсказка: мемоизация не годится для нечистых функций — кэш даст устаревший результат.

Безопасность при параллельном выполнении

Чистые функции не изменяют общий state, следовательно, при параллельном выполнении они не создают гонок и не требуют синхронизации. Это упрощает масштабирование и использование воркеров.

Простая отладка и предсказуемость

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

Когда чистые функции не подходят

  • Взаимодействие с внешними системами: сетевые запросы, чтение/запись в БД, доступ к файловой системе — эти операции сами по себе нечисты.
  • Обновление приложения: UI, хранение состояния сессии, логирование — эти задачи требуют побочных эффектов.
  • Высокая накладная стоимость копирования больших объектных графов. Иногда мутация с контролем (например, с копированием «по необходимости» или использованием структур неизменяемых данных) эффективнее.

Важно: цель — не писать всё чистым, а изолировать чистую бизнес‑логику от нечистой инфраструктуры.

Как превратить нечистую функцию в чистую: мини‑методика

  1. Выявите внешние зависимости и побочные эффекты.
  2. Вынесите чтение/запись в отдельные слои (слой ввода/вывода).
  3. Передавайте все необходимые данные через аргументы.
  4. Не мутируйте входные структуры — создавайте копии или используйте неизменяемые структуры.
  5. Всегда возвращайте значение, даже если это объект с метаданными об ошибке.

Пример рефакторинга:

  • Нечистая версия делает запрос к API и обновляет глобальный state.
  • Рефакторинг: функция получает данные и возвращает результат обработки; сетевой вызов и запись в state выполняются снаружи, с использованием результата чистой функции.

Паттерны и альтернативы

  • Иммутабельность: используйте копии данных или библиотеки (immer) для удобной работы с неизменяемыми структурами.
  • Dependency injection: передавайте функции зависимости (например, генератор случайных чисел) как параметры, чтобы можно было подменять их в тестах.
  • Чистая оболочка (pure wrapper): оборачивайте нечистые операции в чистую функцию, возвращающую промис/результат, а сам побочный эффект выполняйте отдельным слоем.

Ментальные модели для принятия решений

  • «Входы в коробке»: представьте функцию как коробку: все, что ей нужно, должно быть в аргументах; она возвращает результат наружу и ничего не трогает по пути.
  • «Отделение мира»: логика превращается в чистые функции; взаимодействие с миром выполняют адаптеры (I/O). Это шаблон портов и адаптеров (hexagonal architecture).

Контрпримеры и характерные ошибки

  • Использование Date.now() внутри функции для вычисления поведения — делает функцию нечистой.
  • Модификация аргумента объекта внутри функции. Даже если тесты проходят, такое поведение ломает инварианты и может вызвать баги.

Чек‑лист для команды

Разработчик:

  • Все входные данные передаются через параметры.
  • Нет модификации глобальных переменных.
  • Не мутируются переданные объекты.
  • Есть return с ожидаемой структурой.

Код‑ревьювер:

  • Проверить зависимости функции.
  • Проверить, используются ли внешние сервисы внутри функции.
  • Проверить тесты на повторяемость и детерминированность.

Тестер:

  • Написать позитивные и негативные тесты для входов и граничных случаев.
  • Проверить поведение при одинаковых входах несколько раз.
  • Отдельно тестировать интеграцию с адаптерами ввода/вывода.

Критерии приёмки

  • Функция возвращает детерминированный результат для заданного набора входных данных.
  • Нет побочных эффектов (изменение глобальных переменных, console.log, сетевые вызовы) внутри функции.
  • Входные структуры не мутируются (тесты проверяют исходные объекты до и после вызова).

Тест‑кейсы для примера multiply

  1. multiply(0, 5) → 0.
  2. multiply(-1, 5) → -5.
  3. multiply(2, 3) повторно → всегда 6.
  4. Передать нечисловой аргумент → выбрасывает ошибку или возвращает NaN, ожидаемое поведение документировано.

Безопасность и приватность

Чистые функции облегчают безопасность, потому что они не осуществляют прямых операций ввода/вывода. Данные не утекают из функции, если вы явно не возвращаете их. Однако безопасность всё равно зависит от кода, который вызывает функцию и от того, как обрабатываются результаты.

Быстрая таблица сравнения

СвойствоЧистая функцияНечистая функция
ДетерминированностьДаНет
ТестируемостьЛегкоСложно
ПараллелизацияПростаяТребует синхронизации
Подходит для I/OНетДа

Пример решения зависимости от случайности через внедрение зависимостей

function multiplyWithRandom(num, rng) {
  // rng передаётся извне, в тестах можно подменить
  return num * Math.floor(rng() * 10);
}

// В проде
multiplyWithRandom(5, Math.random);

// В тесте
multiplyWithRandom(5, () => 0.5); // детерминированно

Decision flowchart

flowchart TD
  A[Есть ли побочные эффекты?] -->|Да| B[Вынести побочные эффекты в адаптер]
  A -->|Нет| C[Проверить зависимость от внешнего состояния]
  C -->|Зависит| B
  C -->|Не зависит| D[Функция чиста — можно мемоизировать и параллелить]

Краткий глоссарий

  • Побочный эффект: любое наблюдаемое изменение состояния вне функции.
  • Мемоизация: кеширование результатов функции для ускорения повторных вызовов.
  • Иммутабельность: свойство данных не изменяться после создания.

Итог

Чистые функции — мощный инструмент для создания предсказуемой, тестируемой и масштабируемой логики. Они не заменяют необходимость в операциях ввода/вывода, но помогают изолировать бизнес‑логику и снизить сложность системы.

Важно: не стремитесь делать всё чистым любой ценой. Стратегия, которая работает лучше всего, — это отделять чистую логику от нечистых адаптеров и последовательно рефакторить критичные части приложения.

Важно: при рефакторинге проверяйте производительность и читаемость. Иногда контролируемая мутация в локальном контексте может быть оправдана.

Применяйте чек‑листы и методику, описанную выше, чтобы переводить функции в чистый вид там, где это даёт максимум выгоды.

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

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

RDP: полный гид по настройке и безопасности
Инфраструктура

RDP: полный гид по настройке и безопасности

Android как клавиатура и трекпад для Windows
Гайды

Android как клавиатура и трекпад для Windows

Советы и приёмы для работы с PDF
Документы

Советы и приёмы для работы с PDF

Calibration в Lightroom Classic: как и когда использовать
Фото

Calibration в Lightroom Classic: как и когда использовать

Отключить Siri Suggestions на iPhone
iOS

Отключить Siri Suggestions на iPhone

Рисование таблиц в Microsoft Word — руководство
Office

Рисование таблиц в Microsoft Word — руководство