Функциональные приёмы
Чистые функции, каррирование и композиция — кирпичики функционального стиля в JS.
Чистая функция — функция, которая при одних и тех же аргументах всегда возвращает один результат и не имеет побочных эффектов.
Чистые функции и иммутабельность
Чистые функции предсказуемы, легко тестируются и кэшируются. Признак нечистоты — мутация внешних данных. Сравните подходы: нечистый push меняет исходный массив, чистый возвращает новый, не трогая вход:
// чистая: возвращает новый массив, не трогает вход
function addPure(arr, item) { return [...arr, item]; }
const cart = [1, 2, 3];
const result = addPure(cart, 4);
console.log("новый:", result.join(", "));
console.log("исходный не тронут:", cart.join(", "));Вывод:
новый: 1, 2, 3, 4 исходный не тронут: 1, 2, 3
Каррирование
Каррирование превращает функцию многих аргументов в цепочку функций по одному аргументу. Это позволяет «зафиксировать» часть аргументов и переиспользовать частично применённую функцию. Универсальный curry:
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) return fn.apply(this, args);
return (...next) => curried.apply(this, args.concat(next));
};
}
const sum = (a, b, c) => a + b + c;
const cs = curry(sum);
console.log(cs(1)(2)(3));
console.log(cs(1, 2)(3));
console.log(cs(1)(2, 3));
console.log(cs(1, 2, 3));Вывод:
6 6 6 6
Все четыре способа вызова дают один результат: curry накапливает аргументы, пока их не хватит, и только тогда вызывает исходную функцию.
Композиция функций
Композиция собирает большую функцию из маленьких: выход одной идёт на вход следующей. compose применяет функции справа налево, pipe — слева направо (читается естественнее):
const compose = (...fns) => x => fns.reduceRight((acc, fn) => fn(acc), x);
const pipe = (...fns) => x => fns.reduce((acc, fn) => fn(acc), x);
const double = n => n * 2;
const increment = n => n + 1;
const square = n => n * n;
// double(3)=6 -> +1=7 -> square=49
const f = compose(square, increment, double);
console.log("compose(3):", f(3));
const g = pipe(double, increment, square);
console.log("pipe(3):", g(3));Вывод:
compose(3): 49 pipe(3): 49
Декларативная обработка данных
Функциональный стиль раскрывается в цепочках методов массива. Вместо ручных циклов — читаемый конвейер filter → map → reduce, где каждый шаг — чистое преобразование:
const orders = [
{ id: 1, total: 120, paid: true },
{ id: 2, total: 80, paid: false },
{ id: 3, total: 200, paid: true },
{ id: 4, total: 50, paid: true }
];
const revenue = orders
.filter(o => o.paid)
.map(o => o.total)
.reduce((sum, t) => sum + t, 0);
console.log("выручка с оплаченных:", revenue);Вывод:
выручка с оплаченных: 370
Итог
- Чистые функции без побочных эффектов предсказуемы и тестируемы; не мутируйте вход.
- Каррирование фиксирует часть аргументов для переиспользования.
- Композиция (
compose/pipe) и цепочкиfilter/map/reduceделают код декларативным.