Menu

Metodi degli array in JavaScript: map, filter e reduce

I metodi degli array che sostituiscono quasi tutti i tuoi cicli for: map, filter, reduce, find, some ed every. Scopri quali modificano l'array e quali ne restituiscono uno nuovo.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

Gli array hanno una cassetta degli attrezzi

Gli array di JavaScript portano con sé un gran numero di metodi integrati. Quasi tutto ciò per cui scriveresti un ciclo for (trasformare valori, sceglierne alcuni, sommarli) ha un metodo che lo fa in una riga, si legge meglio e si combina facilmente con gli altri.

Il kit di base sono tre metodi: map, filter e reduce. Impara questi e qualcuno dei loro cugini, e il tuo codice pieno di cicli si riduce a qualcosa che capisci con un'occhiata.

Ogni metodo riceve una callback e restituisce qualcosa. Nessuno di loro ha modificato nums: è un concetto che vale la pena assimilare presto.

map: trasformare ogni elemento

map riceve una funzione e la chiama su ogni elemento, raccogliendo i valori restituiti in un nuovo array della stessa lunghezza. Usalo quando vuoi "un output per ogni input".

La callback riceve anche l'indice come secondo argomento, se ti serve: arr.map((item, i) => ...). Se non ti serve, ignoralo.

Un errore comune: usare map quando l'array restituito non ti serve. Se vuoi solo stampare ogni elemento o salvarlo in un database, quello è un lavoro da forEach o da un semplice ciclo.

filter: tenere quelli che corrispondono

filter chiama un predicato (una funzione che restituisce vero o falso) su ogni elemento e tiene quelli che restituiscono un valore truthy. Il nuovo array ha la stessa lunghezza o è più corto.

map e filter si concatenano in modo naturale. Leggi la catena da sinistra a destra come una pipeline:

Prima filtra, poi trasforma: così map lavora solo sugli elementi sopravvissuti.

reduce: ridurre un array a un solo valore

reduce è il più generale dei tre. Gli passi una funzione reducer (accumulator, item) => newAccumulator e un valore iniziale. Percorre l'array, passando ogni elemento al reducer insieme all'accumulatore calcolato fin lì, e restituisce il valore finale dell'accumulatore.

Il risultato non deve per forza essere un numero. Può essere un oggetto, un altro array, una stringa, qualunque cosa tu costruisca:

Passa sempre il valore iniziale (il secondo argomento). Senza, reduce usa il primo elemento come accumulatore iniziale, il che si rompe con gli array vuoti e spesso non fa comunque quello che vuoi.

reduce è potente ma può diventare difficile da leggere quando la logica si complica. Se il tuo reducer supera poche righe, un semplice ciclo for...of è spesso più chiaro.

forEach: effetti collaterali, nessun valore restituito

forEach è come map ma senza l'array restituito. Esiste per quando vuoi fare qualcosa con ogni elemento (stamparlo, chiamare un'API, aggiornare il DOM) e non ti serve una nuova collezione.

Due cose da sapere:

  • forEach restituisce undefined. Non puoi concatenarci dopo .map().
  • Non puoi uscire in anticipo da un forEach con break. Se ti serve un'uscita anticipata, usa for...of oppure some/every.

Se ti ritrovi a scrivere arr.forEach(x => results.push(transform(x))), quello è un map.

find e findIndex: ne basta uno

find restituisce il primo elemento che soddisfa un predicato, oppure undefined se nessuno corrisponde. findIndex restituisce l'indice (oppure -1).

find si ferma alla prima corrispondenza. Non usare filter(...)[0]: scorre tutto l'array solo per buttare via il resto.

some ed every: domande sì o no

some restituisce true se almeno un elemento supera il test. every restituisce true solo se lo superano tutti.

Entrambi si fermano appena possono: some al primo true, every al primo false. Sono lo strumento giusto per domande del tipo "ce n'è almeno uno che…" o "lo fanno tutti…".

slice vs splice: copiare o tagliare

Questi due hanno nomi simili ma fanno cose molto diverse.

slice(start, end) restituisce una copia superficiale di una parte dell'array. Non modifica nulla. end è escluso; omettilo per arrivare fino in fondo.

splice(start, deleteCount, ...items) modifica l'array sul posto. Rimuove deleteCount elementi a partire da start, eventualmente ne inserisce di nuovi, e restituisce gli elementi rimossi.

Per ricordarlo: slice è sicuro (copia), splice opera col bisturi direttamente sull'array.

Metodi che modificano e metodi che non modificano

Questa distinzione conta. Il codice che modifica per sbaglio un array condiviso produce uno dei bug più fastidiosi da rintracciare.

Modificano l'array (cambiano l'originale e di solito restituiscono altro):

  • push, pop, shift, unshift
  • splice, sort, reverse
  • fill, copyWithin

Non modificano l'array (restituiscono un nuovo array o valore, l'originale resta intatto):

  • map, filter, slice, concat
  • flat, flatMap
  • find, findIndex, some, every, includes, indexOf
  • reduce, reduceRight

I due a cui fare attenzione sono sort e reverse: sembrano innocui e modificano l'array in silenzio. Se ti serve una copia ordinata, prima fai uno slice:

Il JavaScript moderno ha anche i gemelli che non modificano: toSorted, toReversed, toSpliced e with. Restituiscono nuovi array e lasciano stare l'originale. Sono supportati da tutti i runtime attuali: usali quando li hai a disposizione.

flat e flatMap

flat appiattisce gli array annidati di un livello (o di più, con un argomento di profondità). flatMap è un map seguito da un flat di un livello: utile quando ogni elemento produce zero o più risultati.

flatMap è il modo pulito per "espandere" gli elementi (un input, molti output) senza un passaggio flat() in più.

Mettiamo tutto insieme

Un piccolo esempio realistico. Data una lista di ordini, calcola il ricavo totale degli ordini completati sopra i 50 $:

Tre metodi, una pipeline, nessun contatore da gestire. Ogni passaggio descrive quello che fa. Potresti unire le due chiamate a filter, ma tenerle separate si legge bene e a volte aiuta durante il debug.

Prossimo passo: Map e Set

Gli array gestiscono bene le sequenze ordinate, ma sono scomodi quando ti servono ricerche veloci per chiave o una collezione di valori unici. JavaScript ha due strutture dati integrate proprio per questi casi, Map e Set, e sono l'argomento della prossima pagina.

Domande frequenti

Qual è la differenza tra map, filter e reduce in JavaScript?

map trasforma ogni elemento e restituisce un nuovo array della stessa lunghezza. filter tiene solo gli elementi che superano un test e restituisce un nuovo array (di solito più corto). reduce percorre l'array e lo riduce a un unico valore: una somma, un oggetto, un altro array, qualunque cosa tu voglia costruire.

Che differenza c'è tra forEach e map?

forEach esegue una funzione per ogni elemento e restituisce undefined: serve per gli effetti collaterali. map esegue una funzione per ogni elemento e restituisce un nuovo array con i risultati. Se ti serve un array trasformato, usa map. Se vuoi solo fare qualcosa per ogni elemento e il risultato non ti serve, usa forEach (o un ciclo for...of).

Quali metodi degli array modificano l'array originale?

Quelli che modificano l'array sono push, pop, shift, unshift, splice, sort, reverse, fill e copyWithin. Tutti gli altri (map, filter, slice, concat, flat, flatMap, find, some, every, reduce) lasciano intatto l'array originale e restituiscono un nuovo valore.

Quando conviene usare slice e quando splice?

slice(start, end) restituisce una copia superficiale di una parte dell'array e non tocca l'originale. splice(start, deleteCount, ...items) invece modifica l'array: rimuove e/o inserisce elementi sul posto e restituisce quelli rimossi. Per ricordarlo: slice è sicuro, splice opera col bisturi.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA