Ispirato dalla scrittura di questa risposta, ho finito per espandere in seguito e scrivere un post sul blog esaminandolo in dettaglio. Consiglio di verificarlo se vuoi sviluppare una comprensione più profonda di come pensare a questo problema: cerco di spiegarlo pezzo per pezzo e alla fine fornisco anche un confronto JSperf, esaminando le considerazioni sulla velocità.
Detto questo, il tl; dr è questo: per realizzare ciò che stai chiedendo (filtraggio e mappatura all'interno di una chiamata di funzione), dovresti usareArray.reduce()
.
Tuttavia, l' approccio più leggibile e (meno importante) di solito significativamente più veloce 2 consiste nell'usare semplicemente il filtro e la mappa concatenati insieme:
[1,2,3].filter(num => num > 2).map(num => num * 2)
Quello che segue è una descrizione di come Array.reduce()
funziona e di come può essere utilizzato per eseguire il filtro e la mappatura in un'unica iterazione. Ancora una volta, se questo è troppo condensato, consiglio vivamente di vedere il post del blog collegato sopra, che è un'introduzione molto più amichevole con esempi chiari e progressione.
Si fornisce ridurre un argomento che è una funzione (solitamente anonima).
Quella funzione anonima accetta due parametri: uno (come le funzioni anonime passate a map / filter / forEach) è l'iterato su cui operare. C'è un altro argomento per la funzione anonima passata per ridurre, tuttavia, che quelle funzioni non accettano, e questo è il valore che verrà passato tra le chiamate di funzione, spesso indicato come memo .
Nota che mentre Array.filter () accetta solo un argomento (una funzione), Array.reduce () accetta anche un secondo argomento importante (sebbene opzionale): un valore iniziale per 'memo' che sarà passato a quella funzione anonima come suo primo argomento, e successivamente possono essere modificati e passati tra le chiamate di funzione. (Se non viene fornito, 'memo' nella prima chiamata di funzione anonima sarà per impostazione predefinita il primo iterato e l'argomento 'iteratee' sarà effettivamente il secondo valore nell'array)
Nel nostro caso, passeremo un array vuoto per iniziare, quindi sceglieremo se iniettare il nostro iterato nel nostro array o meno in base alla nostra funzione: questo è il processo di filtraggio.
Infine, restituiremo il nostro "array in corso" su ogni chiamata di funzione anonima e reduce prenderà quel valore di ritorno e lo passerà come argomento (chiamato memo) alla sua successiva chiamata di funzione.
Ciò consente che il filtro e la mappa avvengano in un'unica iterazione, riducendo della metà il numero di iterazioni richieste, ma facendo solo il doppio del lavoro per ogni iterazione, quindi non viene salvato nulla a parte le chiamate di funzione, che non sono così costose in javascript .
Per una spiegazione più completa, fare riferimento ai documenti MDN (o al mio post a cui si fa riferimento all'inizio di questa risposta).
Esempio di base di una chiamata 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)
versione più succinta:
[1,2,3].reduce((memo, value) => value > 1 ? memo.concat(value * 2) : memo, [])
Si noti che il primo iterato non era maggiore di uno e quindi è stato filtrato. Notare anche l'iniziale Memo, chiamato solo per rendere chiara la sua esistenza e attirare l'attenzione su di esso. Ancora una volta, viene passato come "memo" alla prima chiamata di funzione anonima, quindi il valore restituito dalla funzione anonima viene passato come argomento "memo" alla funzione successiva.
Un altro esempio del classico caso d'uso per memo sarebbe la restituzione del numero più piccolo o più grande in un array. Esempio:
[7,4,1,99,57,2,1,100].reduce((memo, val) => memo > val ? memo : val)
Un esempio di come scrivere la tua funzione di riduzione (questo spesso aiuta a capire funzioni come queste, trovo):
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;
}
L'implementazione reale consente l'accesso a cose come l'indice, ad esempio, ma spero che questo ti aiuti a ottenere una sensazione semplice per il succo.