Код, который легко читать и сложно сломать, — мечта любого разработчика. Функциональное программирование (ФП) даёт инструменты для этого: чистые функции, неизменяемые данные и композицию. В статье разберём, как применять ФП в JavaScript без академической скуки, с примерами и лайфхаками.
Что такое функциональное программирование и зачем оно нужно
Функциональное программирование — это стиль, где вычисления строятся на функциях, а не на изменении состояния. Вместо того чтобы менять переменные и объекты, вы создаёте новые значения. Главные принципы: чистые функции, неизменяемость, функции как граждане первого класса и композиция.
Зачем это нужно? Представьте, что вы готовите салат. Если каждый ингредиент нарезан отдельно и не перемешан с другими, легче контролировать процесс. Так и в коде: чистые функции не зависят от внешнего мира, их проще тестировать и переиспользовать.
Чистые функции: фундамент функционального стиля
Чистая функция — это функция, которая при одинаковых аргументах всегда возвращает одинаковый результат и не имеет побочных эффектов. Побочные эффекты — это изменение внешних переменных, запись в файл, запрос к серверу, вывод в консоль.
Пример грязной функции:
let counter = 0;
function increment() {
counter++;
return counter;
}
Здесь функция зависит от внешней переменной и меняет её. Результат зависит от того, сколько раз её вызвали. Это грязно.
А вот чистая версия:
function increment(value) {
return value + 1;
}
Теперь функция не трогает внешний мир. Её легко тестировать: передали 5 — получили 6, и всегда так.
Неизменяемость: не меняй — создавай новое
В функциональном стиле данные не изменяются. Вместо этого вы создаёте копии с нужными изменениями. В JavaScript для этого есть методы массивов: map, filter, reduce, а для объектов — spread-оператор.
Сравните императивный и функциональный подход к добавлению элемента в массив:
// Императивный: мутируем исходный массив
const numbers = [1, 2, 3];
numbers.push(4);
// numbers теперь [1, 2, 3, 4]
// Функциональный: создаём новый массив
const numbers = [1, 2, 3];
const newNumbers = [...numbers, 4];
// numbers остался [1, 2, 3], newNumbers — [1, 2, 3, 4]
Почему это важно? Когда данные неизменяемы, вы точно знаете, что функция не испортит их «на стороне». Это спасает от багов, когда один модуль неожиданно меняет объект, который использует другой.
Композиция и каррирование: собираем пазл из функций
Композиция — это объединение нескольких функций в одну. Результат одной становится аргументом другой. В JavaScript есть готовая функция compose в библиотеках вроде Ramda или Lodash, но можно написать свою:
const compose = (...fns) => (x) => fns.reduceRight((acc, fn) => fn(acc), x);
const addOne = (n) => n + 1;
const double = (n) => n * 2;
const addOneThenDouble = compose(double, addOne);
console.log(addOneThenDouble(5)); // (5 + 1) * 2 = 12
Каррирование — это преобразование функции от нескольких аргументов в цепочку функций от одного аргумента. Это позволяет создавать частично применённые функции.
function greet(greeting, name) {
return `${greeting}, ${name}!`;
}
const curriedGreet = (greeting) => (name) => `${greeting}, ${name}!`;
const sayHello = curriedGreet('Привет');
console.log(sayHello('Вася')); // Привет, Вася!
Каррирование удобно, когда вы хотите зафиксировать часть аргументов и получить новую функцию.
Практические приёмы и сравнение подходов
Вот несколько приёмов, которые можно внедрить уже сегодня:
- Используйте
map,filter,reduceвместо цикловfor— код становится декларативнее. - Избегайте изменения аргументов функции. Если нужно изменить объект — сделайте копию через
{...obj, field: newValue}. - Для обновления вложенных объектов используйте глубокое копирование или библиотеки вроде Immer.
- Выносите побочные эффекты (запросы, логирование) в отдельные функции, а ядро логики делайте чистым.
Сравним императивный и функциональный подходы в таблице:
| Аспект | Императивный стиль | Функциональный стиль |
|---|---|---|
| Изменение данных | Мутирует исходные структуры | Создаёт новые копии |
| Читаемость | Часто требует вникания в циклы | Декларативен: что делаем, а не как |
| Тестирование | Сложнее из-за побочных эффектов | Легче: чистые функции предсказуемы |
| Переиспользование | Ниже из-за связанности с контекстом | Выше: функции независимы |
Что в итоге
Функциональное программирование в JavaScript — это не религия, а набор приёмов, которые делают код надёжнее. Начните с малого: делайте функции чистыми, не мутируйте данные, используйте map/filter/reduce. Постепенно внедряйте композицию и каррирование. Главное — не фанатизм, а здравый смысл: иногда императивный цикл проще и быстрее.
Помните: цель — не следовать догмам, а писать понятный и поддерживаемый код. ФП даёт для этого мощные инструменты.



