Как я могу построить, в JavaScript цепочки фильтров, в стиле обертки лодашь это?
Чтобы было понятно, задан массив объектов, вероятно, с однородными ключами:
const data = [
{ name: "tomato", isHealthy: true, "calories": 300 },
{ name: "french fries", isHealthy: false, "calories": 1000 },
{ name: "lettuce", isHealthy: true, "calories": 100 },
{ name: "nacho cheese", isHealthy: false, "calories": 1200 },
{ name: "boring chicken", isHealthy: true, "calories": 500 },
];
И несколько фильтров говорят:
const isHealthy = function(items) {
return items.filter(i => i.isHealthy);
};
const caloriesAbove = function(items, calories) {
return items.filter(i => i.calories > calories);
};
Я хотел бы иметь возможность вызывать цепочку фильтров следующим образом:
wrapper(data).isHealthy().caloriesAbove(500).value.map(...)
2 ответа:
Вот как это делает лодаш:
function wrapper(items) { return { value: items, isHealthy() { return wrapper(items.filter(it => it.isHealthy)); }, caloriesAbove(calories) { return wrapper(items.filter(it => it.calories > calories)); }, }; }
Далее, есть ли способ сделать это без необходимости явно разворачивать, чтобы получить значение?
Начиная с ES6 можно расширять массивы:
class Items extends Array { isHealthy() { return this.filter(it => it.isHealthy); } }
Чтобы превратить существующий массив в элементы, просто сделайте
Items.from(array)
илиnew Items(...array)
, тогда вы можете:items .filter(it => it.calories > 2) // native methods can be used, they return Item instances, not Arrays .isHealthy() // our custom methods also work .map(it => it.name)[0] //its a regular array with indices.
Я прочитал ответ, и мне понравилось, как это было сделано @Jonas. Не знал, что можно просто так расширить массив. Защита. получил мой апвот!
С учетом сказанного мне было интересно, насколько полезнее такой подход, когда вы можете просто создать функцию фильтра для обработки нескольких значений и передать ее в фильтр массива:
const data = [ { name: "tomato", isHealthy: true, "calories": 300 }, { name: "french fries", isHealthy: false, "calories": 1000 }, { name: "lettuce", isHealthy: true, "calories": 100 }, { name: "nacho cheese", isHealthy: false, "calories": 1200 }, { name: "boring chicken", isHealthy: true, "calories": 500 }, ]; const myFilterFn = ({isHealthy, calories}) => isHealthy && calories > 200 data.filter(myFilterFn).map(x => console.log(x))
Я вижу значение этого в более общем виде, но для фильтрации это кажется немного излишним.
Только мои 2 цента.