Ramda.js — библиотека, которая избавит вас от reduce и map-каши
- вторник, 4 марта 2025 г. в 00:00:05
Привет, Хабр!
Если вас когда‑либо раздражало, что Array.prototype.map нельзя использовать для объектов или reduce постоянно требует передавать начальное значение, Ramda.js решает эти проблемы, делая код чище, декларативнее и удобнее.
Ramda — это библиотека для функционального программирования в JavaScript, которая по умолчанию не мутирует данные и поддерживает каррирование. В отличие от Lodash, где функциональность чаще заточена под удобство, Ramda больше ориентирована на чистоту кода и прогнозируемость работы функций.
Каррирование — это техника, при которой функция не требует все аргументы сразу, а возвращает новую функцию, ожидающую оставшиеся параметры.
Пример:
import * as R from 'ramda';
const add = R.add(10); // Создаём функцию, которая прибавляет 10
console.log(add(5)); // 15
Такой подход упрощает переиспользование кода и позволяет создавать частично применённые функции.
Вместо длинных цепочек.map().filter().reduce(), где легко запутаться, в Ramda можно использовать функциональную композицию:
R.pipe (слева направо)
R.compose (справа налево)
Допустим, есть массив строк, где встречаются лишние пробелы и разный регистр:
const names = [' Alice ', ' BOB ', ' Eva', ' J'];
На чистом JS:
const normalizeNames = (names) =>
names
.map(name => name.trim())
.map(name => name.toLowerCase())
.filter(name => name.length > 3);
console.log(normalizeNames(names)); // ['alice', 'bob']
С Ramda:
const normalizeNames = R.pipe(
R.map(R.trim),
R.map(R.toLower),
R.filter(name => name.length > 3)
);
console.log(normalizeNames(names)); // ['alice', 'bob']
Стало компактнее и читабельнее.
Предположим, есть API, возвращающее массив пользователей:
[
{ "id": 1, "name": " Alice ", "age": 25, "active": true },
{ "id": 2, "name": " Bob ", "age": 30, "active": false },
{ "id": 3, "name": " Charlie ", "age": 35, "active": true }
]
Задача:
Выбрать только активных пользователей.
Привести их имена к нормальному виду.
Вернуть массив имён.
С Lodash:
import _ from 'lodash';
const processUsers = (users) =>
_.chain(users)
.filter({ active: true })
.map(user => _.trim(user.name).toLowerCase())
.value();
С Ramda:
const processUsers = R.pipe(
R.filter(R.propEq('active', true)),
R.map(R.pipe(R.prop('name'), R.trim, R.toLower))
);
console.log(processUsers(users)); // ['alice', 'charlie']
Ramda избавляет от промежуточных переменных.
В функциональном стиле нельзя мутировать объекты, но Ramda предлагает удобные методы для их изменения.
Добавление и удаление полей (assoc, dissoc)
const user = { id: 1, name: 'Alice', age: 25 };
// Добавить поле
const updatedUser = R.assoc('status', 'active', user);
console.log(updatedUser);
// { id: 1, name: 'Alice', age: 25, status: 'active' }
// Удалить поле
const withoutAge = R.dissoc('age', updatedUser);
console.log(withoutAge);
// { id: 1, name: 'Alice', status: 'active' }
Изменение вложенных структур (evolve)
const user = { name: 'Alice', stats: { points: 10, level: 2 } };
const leveledUp = R.evolve({
stats: { points: R.add(5), level: R.inc }
}, user);
console.log(leveledUp);
// { name: 'Alice', stats: { points: 15, level: 3 } }
Это удобно при обработке сложных JSON‑структур.
Допустим, есть массив заказов, и нужно сгруппировать их по статусу.
const orders = [
{ id: 1, status: 'pending', amount: 50 },
{ id: 2, status: 'completed', amount: 150 },
{ id: 3, status: 'pending', amount: 20 }
];
// Группировка по статусу
const groupedOrders = R.groupBy(R.prop('status'), orders);
console.log(groupedOrders);
/*
{
pending: [
{ id: 1, status: 'pending', amount: 50 },
{ id: 3, status: 'pending', amount: 20 }
],
completed: [
{ id: 2, status: 'completed', amount: 150 }
]
}
*/
Это полезно, например, при рендере таблиц в React.
Хотя Ramda мощна, не стоит использовать её везде. В простых случаях достаточно стандартных методов map, filter, reduce:
const users = [{ name: "Alice" }, { name: "Bob" }];
console.log(users.map(user => user.name));
Ramda полезна там, где:
Много операций над данными.
Нужно поддерживать иммутабельность.
Код должен быть декларативным и легко читаемым.
Используете Ramda? Делитесь комментариях!
А подробнее с Ramda можно ознакомиться здесь.
Будущим разработчикам на JS рекомендую посетить открытые уроки, которые совсем скоро проведут практикующие преподаватели Otus:
5 марта: Быстрый старт в Fullstack-разработку на наглядном примере с API и JavaScript. Записаться
19 марта: Прототипное наследование в JavaScript. Записаться