Натхненний написанням цієї відповіді, я в кінцевому підсумку пізніше розширив і написав допис у блозі, детально описуючи це. Я рекомендую перевірити це якщо ви хочете глибше зрозуміти, як думати про цю проблему - я намагаюся пояснити це поштучно, а також навести порівняння JSperf в кінці, переглядаючи міркування щодо швидкості.
Тим не менш, tl; dr це таке: щоб виконати те, про що ви просите (фільтрування та відображення в межах одного виклику функції), ви б використалиArray.reduce()
.
Однак більш читабельним і (що не менш важливо), як правило, значно швидшим 2 підходом є просто використання фільтра та карти, зв'язаних між собою:
[1,2,3].filter(num => num > 2).map(num => num * 2)
Далі йде опис того Array.reduce()
, як це працює, і як його можна використовувати для фільтрації та картографування за одну ітерацію. Знову ж таки, якщо це занадто стисло, я настійно рекомендую переглянути допис у блозі, зв’язаний вище, що є набагато більш дружнім вступом з чіткими прикладами та прогресом.
Ви даєте аргумент зменшення, який є (як правило, анонімною) функцією.
Ця анонімна функція приймає два параметри - один (як-от анонімні функції, передані в map / filter / forEach) є ітератором, яким слід керувати. Існує ще один аргумент для анонімної функції, переданої для зменшення, однак те, що ці функції не приймають, і це значення, яке буде передаватися між викликами функцій, яке часто називають нагадуванням .
Зауважте, що хоча Array.filter () приймає лише один аргумент (функцію), Array.reduce () також приймає важливий (хоча необов’язковий) другий аргумент: початкове значення для „memo”, яке буде передано в цю анонімну функцію як її перший аргумент, а згодом може бути мутованим і передаватися між викликами функцій. (Якщо його не вказано, тоді 'memo' у першому анонімному виклику функції за замовчуванням буде першим ітератором, а аргумент 'iteratee' насправді буде другим значенням у масиві)
У нашому випадку для початку ми передамо порожній масив, а потім виберемо, вводити ітератор у наш масив чи ні, виходячи з нашої функції - це процес фільтрації.
Нарешті, ми повертаємо наш "масив, що виконується" під час кожного анонімного виклику функції, а зменшення буде приймати це повертане значення і передавати його як аргумент (званий нагадуванням) до наступного виклику функції.
Це дозволяє виконувати фільтр і карту за одну ітерацію, зменшуючи кількість необхідних ітерацій вдвічі - однак виконуючи вдвічі більше роботи за кожну ітерацію, отже, насправді нічого не зберігається, крім викликів функцій, які не так дорогі в JavaScript .
Для більш повного пояснення зверніться до документів MDN (або до мого повідомлення, на яке посилається на початку цієї відповіді).
Основний приклад зменшення дзвінка:
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, [])
Зверніть увагу, що перший ітератор був не більший за одиницю, і тому був відфільтрований. Також зверніть увагу на початкову пам’ятку, названу лише для того, щоб зрозуміти її існування та привернути до неї увагу. Ще раз, воно передається як «нагадування» до першого виклику анонімної функції, а потім повернене значення анонімної функції передається як аргумент «нагадування» до наступної функції.
Іншим прикладом класичного варіанту використання для пам'ятки було б повернення найменшого чи найбільшого числа в масиві. Приклад:
[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;
}
Реальна реалізація дозволяє отримати доступ до таких речей, як індекс, наприклад, але я сподіваюся, це допоможе вам отримати складне відчуття суті цього.