Introduzione
Le funzioni di ordine superiore map, filter e reduce sono tra gli strumenti più utili in JavaScript quando si lavora con array di dati. Spesso vengono presentate in modo astratto, ma il loro vero valore emerge nei casi pratici: trasformare liste, selezionare elementi, calcolare valori aggregati e preparare dati per l’interfaccia utente.
In questo tutorial vediamo un sotto-argomento molto concreto: costruire e ordinare una lista di attività partendo da dati grezzi. L’obiettivo è simulare un piccolo gestionale di task, in cui abbiamo attività con priorità, stato e tempo stimato. Useremo filter per selezionare le attività rilevanti, map per trasformarle in un formato più utile e reduce per ricavare statistiche sintetiche.
Questo approccio è utile in molti contesti reali: to-do list, backlog di progetto, liste di ticket, inventari o qualsiasi array di oggetti che richieda pulizia e trasformazione prima di essere mostrato o elaborato.
Codice completo
const tasks = [
{ id: 1, title: "Scrivere documentazione API", priority: 3, done: false, estimatedHours: 4 },
{ id: 2, title: "Fix bug login mobile", priority: 5, done: true, estimatedHours: 2 },
{ id: 3, title: "Aggiornare dipendenze", priority: 2, done: false, estimatedHours: 3 },
{ id: 4, title: "Refactor componente Navbar", priority: 4, done: false, estimatedHours: 5 },
{ id: 5, title: "Creare test unitari", priority: 5, done: false, estimatedHours: 6 },
{ id: 6, title: "Rimuovere codice morto", priority: 1, done: true, estimatedHours: 1 }
];
// 1) Filtriamo solo le attività ancora aperte
const openTasks = tasks.filter(task => !task.done);
// 2) Ordiniamo le attività aperte per priorità decrescente
const sortedOpenTasks = openTasks.sort((a, b) => b.priority - a.priority);
// 3) Trasformiamo i dati con map per ottenere una lista pronta per la UI
const taskCards = sortedOpenTasks.map(task => ({
label: `${task.title} (priorità ${task.priority})`,
urgency: task.priority >= 4 ? "Alta" : "Media",
estimatedHours: task.estimatedHours
}));
// 4) Usiamo reduce per calcolare statistiche utili
const summary = tasks.reduce(
(acc, task) => {
acc.total += 1;
if (task.done) {
acc.completed += 1;
} else {
acc.open += 1;
}
acc.totalEstimatedHours += task.estimatedHours;
acc.byPriority[task.priority] = (acc.byPriority[task.priority] || 0) + 1;
return acc;
},
{
total: 0,
completed: 0,
open: 0,
totalEstimatedHours: 0,
byPriority: {}
}
);
// Output di esempio
console.log("Attività aperte ordinate:", sortedOpenTasks);
console.log("Schede pronte per UI:", taskCards);
console.log("Riepilogo:", summary); Spiegazione
1. filter: selezionare solo ciò che serve
filter crea un nuovo array contenente solo gli elementi che soddisfano una certa condizione. Nel nostro esempio vogliamo mostrare solo le attività non completate:
const openTasks = tasks.filter(task => !task.done); Qui la condizione !task.done significa “non completata”. Il risultato è un array più piccolo e più significativo, perfetto per essere mostrato in un pannello “attività aperte”.
2. sort: ordinare prima di trasformare
Anche se il focus del tutorial è su map, filter e reduce, in un caso reale l’ordinamento è spesso il passo successivo naturale. Dopo aver filtrato le attività aperte, le ordiniamo per priorità decrescente:
const sortedOpenTasks = openTasks.sort((a, b) => b.priority - a.priority); In questo modo le attività più urgenti compaiono per prime. Attenzione: sort modifica l’array originale. Se vuoi evitare effetti collaterali, puoi creare una copia prima di ordinare:
const sortedOpenTasks = [...openTasks].sort((a, b) => b.priority - a.priority); 3. map: trasformare i dati per la presentazione
map serve a convertire ogni elemento dell’array in un nuovo valore. Nel nostro caso trasformiamo gli oggetti task in una struttura adatta alla UI:
const taskCards = sortedOpenTasks.map(task => ({
label: `${task.title} (priorità ${task.priority})`,
urgency: task.priority >= 4 ? "Alta" : "Media",
estimatedHours: task.estimatedHours
})); Questo passaggio è importante perché separa i dati grezzi dalla loro rappresentazione. In pratica, l’array originale resta legato al dominio applicativo, mentre il risultato di map è già “pronto da mostrare”.
4. reduce: sintetizzare informazioni
reduce è la funzione più potente e spesso la meno intuitiva. Permette di accumulare un risultato finale partendo da tutti gli elementi dell’array. Qui la usiamo per costruire un riepilogo:
const summary = tasks.reduce((acc, task) => {
acc.total += 1;
if (task.done) {
acc.completed += 1;
} else {
acc.open += 1;
}
acc.totalEstimatedHours += task.estimatedHours;
acc.byPriority[task.priority] = (acc.byPriority[task.priority] || 0) + 1;
return acc;
}, {
total: 0,
completed: 0,
open: 0,
totalEstimatedHours: 0,
byPriority: {}
}); Il parametro acc è l’accumulatore, cioè l’oggetto che viene aggiornato a ogni iterazione. Alla fine otteniamo un report con:
- numero totale di attività
- numero di attività completate
- numero di attività aperte
- somma delle ore stimate
- distribuzione delle attività per priorità
Perché questa sequenza è efficace
La catena filter → sort → map → reduce segue un flusso logico molto chiaro:
- filter restringe il dataset
- sort lo ordina secondo una regola di business
- map lo adatta alla visualizzazione o a un formato intermedio
- reduce produce una sintesi finale
Questo tipo di pipeline è facile da leggere, testare e mantenere. Inoltre evita cicli annidati e codice duplicato.
Best practice
- Usa map solo per trasformazioni: se devi solo leggere i dati, non usare map inutilmente.
- Non mutare gli array senza motivo: sort modifica l’array originale, quindi fai una copia se serve preservare i dati.
- Rendi reduce leggibile: se l’accumulatore diventa complesso, spezza la logica in funzioni più piccole.
- Preferisci nomi espliciti: variabili come openTasks, taskCards e summary rendono il codice più chiaro.
- Evita passaggi superflui: se puoi ottenere il risultato con un solo reduce, non concatenare operazioni inutili.
- Gestisci sempre i casi limite: array vuoti, valori nulli o proprietà mancanti possono rompere una pipeline non robusta.
Riepilogo
In questo tutorial abbiamo visto come usare map, filter e reduce in uno scenario pratico: la gestione di una lista di attività ordinabile. Il punto chiave non è memorizzare la sintassi, ma capire il ruolo di ogni funzione:
- filter seleziona i dati rilevanti
- map li trasforma in un formato utile
- reduce costruisce un risultato aggregato
Queste funzioni diventano davvero potenti quando le combini in modo coerente. Invece di scrivere codice lungo e imperativo, puoi descrivere il flusso dei dati in modo più dichiarativo e leggibile. È uno stile molto apprezzato nei progetti moderni, soprattutto quando si lavora con array di oggetti provenienti da API, database o form utente.
Approfondisci con risorse ufficiali
- MDN - Array.prototype.map(): documentazione completa e esempi pratici.
- MDN - Array.prototype.filter(): dettagli sul comportamento del filtro e sui callback.
- MDN - Array.prototype.reduce(): guida approfondita all’accumulatore e ai casi d’uso.
- MDN - Array.prototype.sort(): utile per capire come ordinare correttamente senza errori comuni.
- JavaScript.info: ottima risorsa per ripassare array methods e programmazione funzionale in JavaScript.
