Каррирование  —  это техника, применяемая в функциональном программировании. Она позволяет преобразовать функцию с несколькими аргументами в последовательность функций, каждая из которых принимает один аргумент за раз. Данная концепция названа в честь математика Хаскелла Карри, который представил ее в 1930 году. В JavaScript техника каррирования зарекомендовала себя как мощный инструмент, улучшающий повторное использование кода, его компонуемость и сопровождение. В статье мы подробно исследуем процесс каррирования, объясним его суть и приведем примеры.

Начнем с базового примера. Рассмотрим функцию add, принимающую 2 аргумента и возвращающую их сумму: 

function add(x, y) {
return x + y;
}

console.log(add(3, 4)); // Вывод: 7

Функция add принимает 2 аргумента, x и y, и возвращает их сумму. Теперь выполним каррирование данной функции. Для этого воспользуемся техникой частичного применения: 

function add(x) {
return function(y) {
return x + y;
};
}

console.log(add(3)(4)); // Вывод: 7

В варианте с каррированием функция add принимает один аргумент x и возвращает другую функцию, которая принимает второй аргумент y, после чего выполняет сложение. Это позволяет вызвать add(3) и получить новую функцию, которую можно вызвать с оставшимся аргументом 4.

Каррирование обеспечивает ряд преимуществ. Во-первых, оно позволяет создавать специализированные функции из более общих. Создадим переиспользуемую функцию addOne путем частичного применения функции add:

const addOne = add(1);
console.log(addOne(5)); // Вывод: 6
console.log(addOne(10)); // Вывод: 11

В примере addOne  —  это новая функция, производная от add, которая всегда прибавляет 1 к своему аргументу. Эту функцию можно повсеместно переиспользовать в базе кода без дублирования логики. 

Во-вторых, каррирование делает возможным создание функций высшего порядка, улучшающих компонуемость. Рассмотрим функцию multiply, принимающую 3 аргумента и возвращающую их произведение: 

function multiply(x, y, z) {
return x * y * z;
}

console.log(multiply(2, 3, 4)); // Вывод: 24

Выполняем каррирование функции multiply:

function multiply(x) {
return function(y) {
return function(z) {
return x * y * z;
};
};
}

console.log(multiply(2)(3)(4)); // Вывод: 24

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

const multiplyByTwo = multiply(2);
const multiplyByThree = multiplyByTwo(3);

console.log(multiplyByThree(4)); // Вывод: 24
console.log(multiply(2)(3)(4)); // Вывод: 24

В-третьих, каррирование способствует созданию более гибких функций. Создадим вариации функции, частично применив несколько аргументов и позднее предоставив другие: 

const multiplyByTwoAndThree = multiply(2)(3);

console.log(multiplyByTwoAndThree(5)); // Вывод: 30
console.log(multiplyByTwoAndThree(10)); // Вывод: 60

Каррирование функции multiply упрощает создание специализированных вариантов, ориентированных на конкретные случаи. 

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

function handleClick(action) {
return function(event) {
console.log(`Performing ${action} action on button click.`);
};
}

const handleSaveClick = handleClick('save');
const handleDeleteClick = handleClick('delete');

// Прикрепление обработчиков событий к кнопкам
document.getElementById('saveButton').addEventListener('click', handleSaveClick);
document.getElementById('deleteButton').addEventListener('click', handleDeleteClick);

В примере выполняется каррирование функции handleClick, что позволяет ей принять параметр action. Она возвращает новую функцию, которая при нажатии кнопки логирует соответствующее действие. Частично применяя функцию handleClick, мы создаем специализированные обработчики событий для разных действий (save и delete). Такой подход уменьшает дублирование кода и повышает возможности переиспользования. 

Провести каррирование также можно с помощью таких библиотек, как Lodash и Ramda. Они предоставляют вспомогательные функции, которые упрощают данную операцию. Пример с функцией curry из Lodash: 

const { curry } = require('lodash');

function greet(greeting, name) {
console.log(`${greeting}, ${name}!`);
}

const curriedGreet = curry(greet);

curriedGreet('Hello')('John'); // Вывод: Hello, John!
curriedGreet('Hi')('Sarah'); // Вывод: Hi, Sarah!

Функция curry выполняет каррирование функции greet. Полученная функция curriedGreet вызывается с один аргументом за раз или со всеми сразу. 

Заключение 

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

Читайте также:

Читайте нас в TelegramVK и Дзен


Перевод статьи Sumit kumar Singh: Everything about Currying in JavaScript

Предыдущая статьяРост производительности машинного обучения с Rust. Часть 2
Следующая статьяНавигация во Flutter с использованием AutoRoute