Я недавно написал ответ, и мое мнение изменилось. Я рекомендую проверить мой пост в блоге , который расширяет эту тему и объясняет ее намного лучше. Это также дает сравнение JSperf в конце альтернатив.
TL; DR это:
Чтобы выполнить то, что вы просите (фильтрация и отображение в пределах одного вызова функции), вы должны использовать Array.reduce()
. Тем не менее, более читабельный и обычно быстрее 2 - это просто использовать фильтр и карту, соединенные вместе:
[1,2,3].filter(num => num > 2).map(num => num * 2)
Далее следует описание того, как работает Array.reduce()
, и как его можно использовать для выполнения фильтрации и сопоставления за одну итерацию. Если это слишком сжато, я настоятельно рекомендую посмотреть пост в блоге по ссылке выше, который представляет собой гораздо более дружелюбное введение с ясными примерами и прогрессом.
Вы приводите аргумент сокращения, который является (обычно анонимной) функцией.
Эта анонимная функция принимает два параметра - один (например, анонимные функции, передаваемые в map / filter / forEach) - это итератор, с которым нужно работать. Однако для передачи анонимной функции есть еще один аргумент, заключающийся в том, что эти функции не принимают, и это значение, которое будет передаваться между вызовами функций, часто называемое memo . .
Обратите внимание, что в то время как Array.filter () принимает только один аргумент (функцию), Array.reduce () также принимает важный (хотя и необязательный) второй аргумент: начальное значение «memo», которое будет передано этому анониму функция в качестве первого аргумента, а затем может быть видоизменен и передан между вызовами функций. (Если он не указан, то по умолчанию «memo» в первом вызове анонимной функции будет первым итератором, а аргумент «итератора» фактически будет вторым значением в массиве)
В нашем случае мы передадим пустой массив для запуска, а затем решим, внедрять ли нашего итерируемого в наш массив или нет на основе нашей функции - это процесс фильтрации.
Наконец, мы будем возвращать наш «массив в процессе» при каждом вызове анонимной функции, а Reduce примет это возвращаемое значение и передаст его в качестве аргумента (называемого memo) следующему вызову функции.
Это позволяет фильтровать и отображать карту за одну итерацию, сокращая количество необходимых итераций вдвое. :)
Для более полного объяснения см. MDN или ссылку выше. :)
Базовый пример вызова Reduce:
let array = [1,2,3];
const initialMemo = [];
array = array.reduce((memo, iteratee) => {
// if condition is our filter
if (iteratee > 1) {
// what happens inside the filter is the map
memo.push(iteratee * 2);
}
// this return value will be passed in as the 'memo' argument
// to the next call of this function, and this function will have
// every element passed into it at some point.
return memo;
}, initialMemo)
console.log(array) // [4,6], equivalent to [(2 * 2), (3 * 2)]
более краткая версия:
[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)
// ^this would return the largest number in the list.
Пример того, как написать свою собственную функцию сокращения (это часто помогает понять такие функции, как я нахожу):
test_arr = [];
// we accept an anonymous function, and an optional 'initial memo' value.
test_arr.my_reducer = function(reduceFunc, initialMemo) {
// if we did not pass in a second argument, then our first memo value
// will be whatever is in index zero. (Otherwise, it will
// be that second argument.)
const initialMemoIsIndexZero = arguments.length < 2;
// here we use that logic to set the memo value accordingly.
let memo = initialMemoIsIndexZero ? this[0] : initialMemo;
// here we use that same boolean to decide whether the first
// value we pass in as iteratee is either the first or second
// element
const initialIteratee = initialMemoIsIndexZero ? 1 : 0;
for (var i = initialIteratee; i < this.length; i++) {
// memo is either the argument passed in above, or the
// first item in the list. initialIteratee is either the
// first item in the list, or the second item in the list.
memo = reduceFunc(memo, this[i]);
}
// after we've compressed the array into a single value,
// we return it.
return memo;
}
Реальная реализация позволяет получить доступ к таким вещам, как, например, указатель, но я надеюсь, что это поможет вам легко понять сущность этого.