In quest’articolo parlerò nel dettaglio dei Big Three di Javascript. Capirli è un passo importante per ogni sviluppatore Frontend che non teme la programmazione funzionale e la scrittura di codice di un livello superiore.
Prima di partire voglio dedicare due righe alla programmazione funzionale: in breve è un modo di vedere la creazione di codice, alla pari della classica programmazione imperativa, con la differenza che consente di scrivere in modo molto più pulito, leggibile e testabile, ed è figlia del concetto matematico di Funzione, ossia di una relazione tra insiemi a cui viene associato ad uno o più elementi di un insieme, uno ed un solo elemento dell’altro insieme (Si.. stiamo proprio parlando del concetto di Dominio e di Codominio). Cercando in rete riuscirete sicuramente ad approfondire in quanto è un argomento sempre più popolare tra tutti gli sviluppatori.
Dopo questa breve introduzione, partiamo con i famigerati Big Three di Javascript e del motivo per cui sono preferibili ai normali Loop e cicli. Per spiegarlo userò un approccio pragmatico e ricco di esempi di casi reali.
Presenterò gli esempi usando sia l’approccio con Arrow Function sia l’approccio ES5, limitandomi a sottolineare quanto la pulizia del codice aumenti drasticamente.
FILTER IN JAVASCRIPT
Partiamo dal metodo FILTER e mettiamolo a confronto con un normale for.
Come filtrereste un Array di oggetti come questo scegliendo solo le auto di tipo “minivan”?
Usando un normale ciclo for avremmo una soluzione di questo tipo:
Questo codice funziona perfettamente, nulla da dire. Ma se volessimo effettuare operazioni più complesse e che magari dovranno lavorare direttamente sull’insieme dei minivan? Ecco che a questo for se ne aggiungerà un altro che farà altre operazioni e così via, facendo così aumentare il numero di righe e peggiorando drasticamente la leggibilità del codice.
Vediamo l’implementazione utilizzando il metodo Filter.
- Approccio Arrow function:
- Approccio ES5:
in molte meno righe e senza dover gestire indici e altre variabili esterne, abbiamo ottenuto lo stesso risultato! Tutto ciò è veramente fantastico!
Entriamo un attimo nel dettaglio delle implementazioni appena esposte e di come funzionano: il metodo Filter prende come parametro una funzione (callback) che viene eseguita su ogni elemento dell’array su cui viene invocata. La Callback deve tornare un Boolean, quindi true o false, se la condizione ritorna true allora l’elemento verrà aggiunto nell’array finale risultante, in quanto il metodo Filter restituisce un nuovo Array e non agisce sull’originale!
L’esempio più semplice è il classico in cui avete un array di numeri come questo:
e dovete recuperare solo quelli pari. L'implementazione seguendo l'approccio delle arrow function sarebbe di questo tipo:
in poche parole se ELEM (che sarebbe il singolo numero dell’array) soddisfa la condizione del return, allora sarà aggiunto in filtered!
MAP IN JAVASCRIPT
In modo molto simile si comporta il metodo Map: anche lui accetta una callback che viene eseguita su ogni singolo elemento dell’array. Il suo obiettivo è applicare delle logiche all’elemento in modo da ritornare un nuovo Array in cui ogni dato è stato Mappato usando la callback.
Con qualche esempio sarà tutto più chiaro.
Immaginiamo di riprendere lo stesso array di numeri di prima
e desiderare un array in cui tutti gli elementi sono raddoppiati, insomma.. mappati diversamente!
- Approccio Arrow function:
- Approccio ES5:
Come vedete le regole sono le stesse del metodo Filter! Ad ogni elemento dell’array viene applicata una computazione che lo modifica e lo inserisce in un nuovo array risultante.
Un esempio più complesso potrebbe essere, partendo dall’array di Cars a inizio articolo, il seguente: modificare tutte gli elementi di tipo minivan, aggiungendo il campo insurance.
Riposto l'oggetto delle cars di sopra per avere un’immagine più chiara
Una soluzione sarebbe:
Avete notato l’utilizzo dello spread operator per recuperare tutte le proprietà della car (color, type, registration e capacity)? La proprietà insurance semplicemente si accoderà alle altre esistenti.
I più attenti avranno visto che il contenuto del return è racchiuso tra delle graffe, ciò consente di preservare l’oggetto originale e prenderne tutti i suoi valori per crearne una copia con l’aggiunta della insurance.
Il risultato sarà sempre un array di oggetti di questo tipo, dove ogni elemento avrà la nuova proprietà valorizzata ad undefined in quanto è stata solo aggiunta:
REDUCE IN JAVASCRIPT
Il Metodo Reduce è un pochino più complesso da comprendere, specialmente per chi è alle prime armi. Partiamo da un esempio molto carino sfruttando lo stesso array di macchine di prima: immaginiamo di voler cercare quella con la capacità maggiore, normalmente con un for avremmo creato una variabile di appoggio e di volta in volta avremmo controllato ogni oggetto corrente con il primo salvato, qualcosa del genere:
e poi iteriamo su tutti gli elementi restanti partendo dal secondo
ed ecco che troveremo la macchina con la capacità maggiore o perlomeno la prima in caso di macchine con capacità identiche.
Vediamo il corrispettivo utilizzando il metodo Reduce.
- Approccio Arrow function:
A prima vista può sembrare difficile da comprendere ma se vi soffermate un attimo a capire sarà tutto chiaro, innanzitutto la logica parte dopo la freccia ( => ), tutto ciò messo dopo questo simbolo è direttamente ritornato come risultato. Dopodiché parte il controllo della capacità utilizzando l'operatore ternario, quindi se si verifica che accumulator.capacity sia maggiore o uguale dell’accumulator.capacity allora accumulator resterà invariato, altrimenti sarà sostituito da currentCar.
- Approccio ES5:
Quindi, ricapitolando, Reduce ha un solo scopo: tirare fuori un solo risultato dall’array su cui viene chiamato! Come i metodi Filter e Map, esegue una callback su ogni singolo elemento, prendendo come parametri l’accumulator o accumulatore e come secondo parametro l’elemento corrente dell’array (NOTA BENE: al primo giro saranno identici). L’elemento di partenza del metodo sarà cars[0] il quale viene specificato in fondo, dopo la callback.
In poche parole si passa l’elemento di partenza che diventerà l'accumulatore, si controlla con l’elemento corrente e se la condizione viene soddisfatta l'accumulatore sarà aggiornato con il nuovo dato e così via fino alla fine dell’array.
L’esempio più famoso è quello in cui si dimostra come tornare la somma di tutti gli elementi:
La soluzione con reduce è la seguente:
La prima iterazione avrà accumulator = 0 e currentValue = 1 e dato che siamo sul primo elemento e non c’è nessun elemento precedente, viene usato lo zero in fondo cioè il secondo parametro. A questo punto viene fatta la somma (quindi 1).
Alla seconda iterazione la funzione viene chiamata con accumulator = 1 (risultato dell’iterazione precedente!) e currentValue = 2. Anche in questo caso verrà eseguita la somma (quindi 3), e così via fino ad ottenere 30, cioè la somma di tutti i numeri.
Un’ultima caratteristica importante dei Big Three è la loro componibilità. Come dei pezzi di un puzzle questi 3 metodi si incastrano perfettamente, permettendo di eseguire operazioni complesse in un modo elegante e pulito.
Un esempio molto carino e semplice potrebbe essere, partendo dall’array dei numeri di prima, prendere solo i numeri pari, moltiplicarli per 3 e successivamente sommarli:
Il risultato sarà 42, immaginate ora di doverlo fare con dei semplici loop come For o While.. scrivetemi quando avrete provato e vediamo le differenze 😀
Conoscere questi 3 metodi è la chiave per poter salire di livello come sviluppatori Frontend ed affacciarsi senza alcun problema alla risoluzione dei problemi più comuni quando si ha a che fare con rest api o con qualsiasi altro dato che necessiti di essere gestito nel modo più pulito possibile!
Come ho dimostrato, tutto ciò è facilmente replicabile con normali For, ma perchè guidare un’utilitaria se si può usare una Ferrari e per giunta gratis? A voi la scelta.