Каррінг — це потужна техніка функціонального програмування, яка покращує читаність, багаторазовість та підтримуваність коду. Розбиваючи функцію з кількома аргументами на ряд функцій, кожна з яких приймає один аргумент, каррінг дозволяє ефективніше управляти складністю. Ключовим елементом, який забезпечує каррінг, є замикання (closures), які "пам'ятають" стан змінних у своїй лексичній області видимості. У цьому дописі ми розглянемо, як працює каррінг, як він залежить від замикань та реальні приклади, де він особливо корисний.
Як каррінг залежить від замикань
У JavaScript замикання формуються, коли функція зберігає доступ до змінних із зовнішньої області, навіть після того, як зовнішня функція виконалася. Каррінг використовує це, створюючи проміжні функції, які "пам'ятають" аргументи, передані раніше.
Приклад: Просте додавання за допомогою каррінгу
const add = (a) => (b) => a + b;
// Створення замикань
const add5 = add(5); // 'add5' пам'ятає a = 5
console.log(add5(3)); // Виводить: 8
У цьому прикладі виклик add(5)
створює замикання, зберігаючи значення a = 5
. Коли викликається add5(3)
, внутрішня функція отримує збережене значення a
і обчислює результат.
Переваги каррінгу
- Збереження стану через замикання (closures): Каррінг "пам'ятає" аргументи, дозволяючи заздалегідь налаштовувати конфігурації.
- Покращена повторне використання коду: Функції з попередньо завантаженими параметрами можна повторно використовувати без повторного визначення поведінки.
- Покращена читаність: Розбиває складні функції на керовані, комбіновані частини.
Реальні застосування каррінгу
1. Попереднє завантаження конфігурацій
Каррінг спрощує повторювані завдання, дозволяючи попередньо завантажувати базові конфігурації.
Без каррінгу:
function fetchData(baseUrl, endpoint, params) {
const query = new URLSearchParams(params).toString();
return fetch(`${baseUrl}${endpoint}?${query}`).then((res) => res.json());
}
// Багаторазові та повторювані виклики
fetchData('https://api.example.com', '/users', { active: true });
З каррінгом:
const fetchData = (baseUrl) => (endpoint) => (params) => {
const query = new URLSearchParams(params).toString();
return fetch(`${baseUrl}${endpoint}?${query}`).then((res) => res.json());
};
// Попереднє завантаження базової конфігурації
const api = fetchData('https://api.example.com');
const fetchUsers = api('/users');
fetchUsers({ active: true });
2. Обробка подій у React
У React каррінг може спростити обробники подій, прив'язуючи конкретні стани до зворотних викликів (callback).
Без каррінгу:
function handleInput(event, fieldName) {
console.log(`${fieldName}: ${event.target.value}`);
}
handleInput(e, 'username')} />;
З каррінгом:
const handleInput = (fieldName) => (event) => {
console.log(`${fieldName}: ${event.target.value}`);
};
;
3. Інтернаціоналізація (i18n)
Управління перекладами часто передбачає повторне вказування мовних кодів. Каррінг спрощує цей процес.
Без каррінгу:
function translate(lang, key) {
const translations = { en: { hello: "Hello" }, es: { hello: "Hola" } };
return translations[lang][key];
}
translate('en', 'hello');
З каррінгом:
const translate = (lang) => (key) => {
const translations = { en: { hello: "Hello" }, es: { hello: "Hola" } };
return translations[lang][key];
};
const tEnglish = translate('en');
console.log(tEnglish('hello'));
# Middleware в Express.js
Каррінг покращує модульність логіки проміжного програмного забезпечення (middleware).
**Без каррінгу:**
function checkPermission(req, res, next, role) {
if (req.user.role === role) next();
else res.status(403).send('Forbidden');
}
app.get('/admin', (req, res, next) => checkPermission(req, res, next, 'admin'), handler);
```
З каррінгом:
const checkPermission = (role) => (req, res, next) => {
if (req.user.role === role) next();
else res.status(403).send('Forbidden');
};
app.get('/admin', checkPermission('admin'), handler);
5. Динамічна логіка валідації
Каррінг робить валідацію повторно використовуваною та виразною.
Без каррінгу:
function validate(value, validator, error) {
return validator(value) ? null : error;
}
validate('', (v) => !!v, 'Required');
З каррінгом:
const validate = (validator) => (error) => (value) => {
return validator(value) ? null : error;
};
const isRequired = validate((v) => !!v)('Required');
console.log(isRequired(''));
Коли використовувати каррінг
Каррінг найкраще підходить для сценаріїв, що включають:
- Попереднє завантаження конфігурацій: запити до API, рівні логування або налаштування користувача.
- Комбіновані функції: створення конвеєрів повторно використовуваної логіки.
- Динамічна логіка: валідації, обробники подій (Event Handlers) та інтернаціоналізація (i18n).
Висновок
Каррінг, реалізований через замикання (closures), перетворює повторюваний, об'ємний код в елегантні, модульні рішення. Хоча він може збільшити складність для простих завдань, його переваги в читаності, повторному використанні та підтримуваності роблять його основою функціонального програмування. Коли його використовувати розумно, каррінг відкриває світ можливостей, даючи розробникам змогу писати чистий, масштабований і ефективний код.
Перекладено з: Understanding Currying and Its Real-World Applications