JS Advanced

Каррирование (Currying)

Понять, как превратить f(a, b, c) в f(a)(b)(c), зачем это нужно, и когда каррирование уместно.

Продвинутый (Advanced)

Кратко

Каррирование — превращение функции с несколькими аргументами в цепочку функций с одним аргументом. f(a, b, c) → f(a)(b)(c). Полезно для создания специализированных функций из общих. Но в обычном коде встречается редко.


Подробно

Простое каррирование: function add(a) { return function(b) { return a + b; }; }

const add5 = add(5); console.log(add5(3)); // 8 console.log(add5(10)); // 15

Каррирование сiple application: function log(level, timestamp, message) { console.log([${level}] ${timestamp}: ${message}); }

// Каррированная версия function curriedLog(level) { return function(timestamp) { return function(message) { console.log([${level}] ${timestamp}: ${message}); }; }; }

const errorLog = curriedLog('ERROR')('2024-01-01'); errorLog('Something failed'); // [ERROR] 2024-01-01: Something failed

Универсальная утилита: function curry(fn) { return function curried(...args) { if (args.length >= fn.length) { return fn.apply(this, args); } return function(...args2) { return curried.apply(this, args.concat(args2)); }; }; }

const curriedAdd = curry((a, b, c) => a + b + c); curriedAdd(1)(2)(3); // 6 curriedAdd(1, 2)(3); // 6 curriedAdd(1)(2, 3); // 6


Ментальная модель

Каррирование — как пошаговая инструкция. Вместо «Сделай A, B и C сразу» — «Сделай A. Получил? Теперь B. Получил? Теперь C.» Каждый шаг фиксирует один аргумент.


Примеры

**Самый простой:**

javascript
function multiply(a) {
  return (b) => a * b;
}

const double = multiply(2);
const triple = multiply(3);

console.log(double(5)); // 10
console.log(triple(5)); // 15

Простейшее каррирование: создание специализированных функций.

**Простой:**

javascript
// Curry утилита
function curry(fn) {
  return function curried(...args) {
    return args.length >= fn.length
      ? fn(...args)
      : (...more) => curried(...args, ...more);
  };
}

const sum = curry((a, b, c) => a + b + c);

console.log(sum(1)(2)(3)); // 6
console.log(sum(1, 2)(3)); // 6
console.log(sum(1)(2, 3)); // 6

Универсальная curry утилита.

**Реальный пример:**

javascript
// Каррирование для фильтрации
const users = [
  { name: 'Анна', age: 25 },
  { name: 'Борис', age: 30 },
  { name: 'Вера', age: 20 },
];

const filterBy = curry((key, value, arr) =>
  arr.filter(item => item[key] === value)
);

const filterByAge = filterBy('age');
const adults = filterByAge(25);
console.log(adults); // [{ name: 'Анна', age: 25 }]

Каррирование для создания специализированных фильтров.


Частые ошибки

**Неправильно:** Каррировать каждую функцию

**Почему:** Каррирование полезно только для специфических паттернов. Большинство функций не нуждаются в каррировании.

**Правильно:** Каррируйте только когда это упрощает код: фабрики функций, pipeline, callback'и.

**Неправильно:** Путать каррирование и partial application

**Почему:** Каррирование: f(a,b,c) → f(a)(b)(c). Partial application: f(a,b,c)(1) → фиксирует один аргумент.

**Правильно:** Каррирование — это частичный случай partial application.


Важно запомнить

  • f(a,b,c) → f(a)(b)(c) — каррирование
  • Создаёт специализированные функции из общих
  • Полезно для: фабрик, pipeline, callback'ов
  • В обычном коде встречается редко
  • Functional programming паттерн

Связь

Назад: Вы знаете функции (J9) и стрелочные функции (J10). Каррирование преобразует сигнатуры функций.

Вперёд: Следующий урок (JV17) — побитовые операторы — низкоуровневые операции над числами.

Материалы курса JS Advanced — PROlab Academy.