#javascript #arrays #object #functional-programming
#javascript #массивы #объект #функциональное программирование
Вопрос:
У меня есть функция, которая возвращает отфильтрованный результат на основе строки в объекте (если она существует или нет)
let foo = nodes.reduce((arr, cur) => {
cur.classes.split(' ').filter((el) => {
if (el === 'foo') arr.push(cur)
})
return arr;
}, []);
Таким образом, он просто возвращает все объекты в массиве, который содержит ‘foo’ в classes object
Этот, например:
let nodes = [
{node: 'h1', classes: 'foo'},
{node: 'p', classes: 'bar'},
{node: 'p', classes: 'baz xxx'},
{node: 'h2', classes: 'bar baz foo'},
{node: 'ul', classes: 'poop foo'}
]
Но моя интуиция подсказывает, что функцию можно написать проще и лаконичнее. Есть идеи?
Ответ №1:
Вы могли бы использовать просто Array#filter
.
let nodes = [{node: 'h1', classes: 'foo'}, {node: 'p', classes: 'bar'}, {node: 'p', classes: 'baz xxx'}, {node: 'h2', classes: 'bar baz foo'}, {node: 'ul', classes: 'poop foo'}],
foo = nodes.filter(a => a.classes.split(' ').some(b => b === 'foo'));
console.log(foo);
Ответ №2:
Как обычно, @NinaScholz предлагает отличный и простой подход. Вам было бы хорошо следовать ее совету.
Лично мне хотелось бы немного подробнее рассмотреть эту проблему и продемонстрировать, как можно комбинировать более мелкие, повторно используемые функции для достижения желаемого эффекта. Я надеюсь, что этот ответ поможет вам увидеть, что функциональное программирование на JavaScript легко выходит за рамки встроенных прототипных методов.
Комментарии помогают вам понять типы, но они совершенно необязательны.
// comp :: (b -> c) -> (a -> b) -> (a -> c)
const comp = f => g => x => f (g (x));
// filter :: (a -> Boolean) -> [a] -> [a]
const filter = f => xs => xs.filter(f);
// some :: (a -> Boolean) -> [a] -> Boolean
const some = f => xs => xs.some(f);
// eq :: (String a, Number a) => a -> a -> Boolean
const eq = x => y => y === x;
// nodeClasses :: Node -> [String]
const nodeClasses = ({classes}) => classes.split(' ');
// nodesWithClass :: String -> [Node] -> [Node]
const nodesWithClass = c => filter (comp (some (eq (c))) (nodeClasses));
// nodes :: [Node]
let nodes = [
{node: 'h1', classes: 'foo'},
{node: 'p', classes: 'bar'},
{node: 'p', classes: 'baz xxx'},
{node: 'h2', classes: 'bar baz foo'},
{node: 'ul', classes: 'poop foo'}
];
console.log(nodesWithClass('foo') (nodes));
Комментарии:
1. @NinaScholz, в своем ответе я назвал вас женщиной, но я не хочу делать никаких оскорбительных предположений. Пожалуйста, поправьте меня, если я ошибаюсь ^_ ^
Ответ №3:
В качестве альтернативы «фильтровать некоторые», как показано Ниной, немного другой подход.
Выглядит не так чисто, но более производительно (насколько важна производительность при такой простой задаче).
let nodes = [
{node: 'h1', classes: 'foo'},
{node: 'p', classes: 'bar'},
{node: 'p', classes: 'foo-bar'},
{node: 'p', classes: 'baz xxx'},
{node: 'h2', classes: 'bar baz foo'},
{node: 'ul', classes: 'poop foo'}
];
let foo = nodes.filter(node => (' ' node.classes ' ').contains(' foo '));
Комментарии:
1. Также хорошее решение, спасибо, Томас. Я сохраню его. 🙂