Вдохновленный написанием этого ответа, я позже расширил и написал сообщение в блоге, в котором подробно рассказывалось об этом. Я рекомендую проверить это, если вы хотите глубже понять, как думать об этой проблеме - я пытаюсь объяснить это по частям, а также в конце провожу сравнение JSperf, не обращая внимания на соображения скорости.
Тем не менее, tl; dr заключается в следующем: чтобы выполнить то, что вы просите (фильтрация и отображение в одном вызове функции), вы должны использоватьArray.reduce()
.
Однако более читаемый и (что менее важно) обычно значительно более быстрый подход 2 - это просто использовать объединенные вместе фильтр и карту:
[1,2,3].filter(num => num > 2).map(num => num * 2)
Далее следует описание того, как это Array.reduce()
работает, и как его можно использовать для выполнения фильтрации и сопоставления за одну итерацию. Опять же, если это слишком сжато, я настоятельно рекомендую посмотреть сообщение в блоге, указанное выше, которое является гораздо более дружелюбным вступлением с четкими примерами и прогрессом.
Вы даете reduce аргумент, который является (обычно анонимной) функцией.
Эта анонимная функция принимает два параметра: один (например, анонимные функции, переданные в map / filter / forEach) - это итерация, над которой нужно работать. Однако есть еще один аргумент для анонимной функции, переданной для уменьшения, что эти функции не принимают, и это значение, которое будет передаваться между вызовами функций, часто называемое памяткой .
Обратите внимание, что в то время как Array.filter () принимает только один аргумент (функцию), Array.reduce () также принимает важный (хотя и необязательный) второй аргумент: начальное значение для 'memo', которое будет передано этой анонимной функции как ее первый аргумент и впоследствии может быть изменен и передан между вызовами функций. (Если он не указан, то «memo» в первом вызове анонимной функции по умолчанию будет первым итератором, а аргумент «итерация» фактически будет вторым значением в массиве)
В нашем случае мы передадим пустой массив для запуска, а затем выберем, вставлять ли нашего итератора в наш массив или нет, на основе нашей функции - это процесс фильтрации.
Наконец, мы возвращаем наш «массив в процессе выполнения» при каждом вызове анонимной функции, а reduce примет это возвращаемое значение и передаст его в качестве аргумента (называемого памяткой) своему следующему вызову функции.
Это позволяет выполнять фильтрацию и отображение за одну итерацию, сокращая количество требуемых итераций вдвое - просто делая в два раза больше работы на каждой итерации, поэтому на самом деле ничего не сохраняется, кроме вызовов функций, которые не так дороги в javascript .
Для более полного объяснения обратитесь к документации MDN (или к моему сообщению, указанному в начале этого ответа).
Базовый пример вызова Reduce:
let array = [1,2,3];
const initialMemo = [];
array = array.reduce((memo, iteratee) => {
if (iteratee > 1) {
memo.push(iteratee * 2);
}
return memo;
}, initialMemo)
console.log(array)
более емкая версия:
[1,2,3].reduce((memo, value) => value > 1 ? memo.concat(value * 2) : memo, [])
Обратите внимание, что первая итерация была не больше единицы и поэтому была отфильтрована. Также обратите внимание на initialMemo, названный просто для того, чтобы прояснить его существование и привлечь к нему внимание. И снова он передается как «памятка» при первом вызове анонимной функции, а затем возвращаемое значение анонимной функции передается в качестве аргумента «памятка» следующей функции.
Другой пример классического варианта использования memo - это возврат наименьшего или наибольшего числа в массиве. Пример:
[7,4,1,99,57,2,1,100].reduce((memo, val) => memo > val ? memo : val)
Пример того, как написать собственную функцию уменьшения (я нахожу, это часто помогает понять подобные функции):
test_arr = [];
test_arr.my_reducer = function(reduceFunc, initialMemo) {
const initialMemoIsIndexZero = arguments.length < 2;
let memo = initialMemoIsIndexZero ? this[0] : initialMemo;
const initialIteratee = initialMemoIsIndexZero ? 1 : 0;
for (var i = initialIteratee; i < this.length; i++) {
memo = reduceFunc(memo, this[i]);
}
return memo;
}
Реальная реализация позволяет получить доступ, например, к таким вещам, как индекс, но я надеюсь, что это поможет вам легко понять его суть.