Функциональное программирование (ФП) часто кажется чем-то сложным и академичным. На самом деле это набор простых приёмов, которые помогают писать более предсказуемый и удобный для тестирования код. В этой статье разберём, как применять ФП в JavaScript без боли и лишней теории.
Что такое функциональное программирование и зачем оно нужно
Функциональное программирование — это подход, при котором программа строится из чистых функций и неизменяемых данных. Вместо того чтобы менять состояние и писать циклы с побочными эффектами, вы описываете, что нужно сделать, а не как.
Главные плюсы ФП в JavaScript:
- Код проще тестировать и отлаживать — функции предсказуемы.
- Меньше багов из-за случайных изменений общих данных.
- Легче переиспользовать и комбинировать функции.
- Код становится декларативнее и читабельнее.
JavaScript не является чисто функциональным языком, но поддерживает многие концепции: функции высшего порядка, замыкания, стрелочные функции и методы массивов.
Чистые функции — основа основ
Чистая функция — это функция, которая:
- Возвращает один и тот же результат при одинаковых аргументах.
- Не имеет побочных эффектов (не меняет внешние переменные, не пишет в DOM, не делает запросы).
Пример грязной функции:
let counter = 0;
function increment() {
counter++;
return counter;
}
Здесь функция меняет внешнюю переменную — это побочный эффект. Чистый вариант:
function increment(value) {
return value + 1;
}
Теперь результат зависит только от аргумента. Такие функции легко тестировать и комбинировать.
Неизменяемость: не мутируйте данные
В функциональном стиле данные не изменяются после создания. Вместо изменения массива или объекта вы создаёте новый. В JavaScript для этого есть удобные методы.
Плохо (мутация):
const numbers = [1, 2, 3];
numbers.push(4); // мутация
Хорошо (создание нового массива):
const numbers = [1, 2, 3];
const newNumbers = [...numbers, 4]; // новый массив
Для объектов используйте spread-оператор:
const user = { name: 'Alice', age: 25 };
const updatedUser = { ...user, age: 26 };
Неизменяемость особенно важна в React и Redux, но полезна и в обычном коде — она предотвращает неожиданные изменения данных.
Функции высшего порядка и методы массивов
Функция высшего порядка — это функция, которая принимает другую функцию как аргумент или возвращает функцию. В JavaScript это обычное дело: map, filter, reduce — всё это функции высшего порядка.
Пример использования map для преобразования массива:
const numbers = [1, 2, 3];
const doubled = numbers.map(n => n * 2); // [2, 4, 6]
filter для отбора элементов:
const numbers = [1, 2, 3, 4];
const even = numbers.filter(n => n % 2 === 0); // [2, 4]
reduce для агрегации:
const numbers = [1, 2, 3, 4];
const sum = numbers.reduce((acc, n) => acc + n, 0); // 10
Эти методы позволяют писать декларативный код без циклов и временных переменных.
Каррирование и композиция функций
Каррирование — это преобразование функции от нескольких аргументов в последовательность функций от одного аргумента. Это помогает создавать переиспользуемые функции.
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return function(...args2) {
return curried.apply(this, args.concat(args2));
};
}
};
}
const add = (a, b) => a + b;
const curriedAdd = curry(add);
const addFive = curriedAdd(5);
console.log(addFive(3)); // 8
Композиция — это объединение нескольких функций в одну. Например, есть функции trim, toLowerCase, capitalize. Можно создать функцию, которая применяет их последовательно.
const compose = (...fns) => (x) => fns.reduceRight((acc, fn) => fn(acc), x);
const trim = str => str.trim();
const toLowerCase = str => str.toLowerCase();
const capitalize = str => str.charAt(0).toUpperCase() + str.slice(1);
const formatName = compose(capitalize, toLowerCase, trim);
console.log(formatName(' aLICE ')); // 'Alice'
Композиция позволяет строить сложные преобразования из простых функций.
Практические советы и сравнение подходов
Вот несколько лайфхаков для внедрения ФП в ваш код:
- Начинайте с малого: заменяйте циклы на
map,filter,reduce. - Избегайте изменения аргументов функций — возвращайте новые значения.
- Используйте
constвместоletвезде, где возможно. - Для сложной логики разбивайте её на маленькие чистые функции.
- Используйте библиотеки вроде Lodash/fp или Ramda для готовых функциональных утилит.
Сравним императивный и функциональный подходы на примере задачи: получить имена пользователей старше 18 лет.
| Подход | Код | Плюсы | Минусы |
|---|---|---|---|
| Императивный | |
Понятно новичкам | Больше кода, легче ошибиться |
| Функциональный | |
Кратко, декларативно, легко читать | Требует привычки |
Как видите, функциональный подход выигрывает в читаемости и компактности.
Что в итоге
Функциональное программирование — это не серебряная пуля, но мощный инструмент. Начните с чистых функций и неизменяемости, постепенно внедряйте композицию и каррирование. Ваш код станет чище, тесты — проще, а багов — меньше.
Помните: цель не в том, чтобы использовать ФП везде, а в том, чтобы писать понятный и надёжный код. Экспериментируйте, пробуйте, и вы увидите, как JavaScript заиграет новыми красками.



