Ordinare un elenco senza alterare lo stato originale, raggruppare i risultati per categoria ed elaborare dati che arrivano in modo asincrono: sono attività comuni, ma per anni ognuna ha richiesto il proprio schema. Tra ES2022 ed ES2026, JavaScript ha introdotto metodi nativi per diverse di queste operazioni. Seguiamo il percorso con un piccolo catalogo di prodotti, dal modello fino a una trasformazione asincrona.
JavaScript è il linguaggio; ECMAScript ne definisce il nucleo e lo standard. MDN spiega che le edizioni vengono pubblicate ogni anno e che i motori integrano le novità secondo i propri calendari. Perciò, il fatto che una funzionalità figuri in un’edizione non garantisce che sia disponibile in qualsiasi browser o versione di Node.js.
Preparare l’esercizio
Salva ogni esempio in un file con estensione .mjs ed eseguilo con Node.js. I blocchi sono indipendenti: ognuno contiene i propri dati e può essere provato separatamente. Poiché il supporto dipende dal motore, verifica che le API specifiche di ogni esercizio siano disponibili nell’ambiente in cui eseguirai il codice; non basta che il file sia un modulo.
node ejercicio.mjs
Il filo conduttore sarà un piccolo catalogo. Iniziamo con due modifiche di ES2022 che aiutano a rappresentare i dati e a interrogare gli oggetti con maggiore precisione.
Dall’incapsulamento dello stato all’ordinamento senza mutazioni
1. ES2022: proteggere i dati del modello
I campi privati con # non sono solo una convenzione di denominazione: l’accesso dall’esterno della classe non è consentito. In questo esempio, l’inventario controlla la propria quantità ed espone un’operazione per modificarla. Object.hasOwn(), anch’esso introdotto in ES2022, verifica se una proprietà appartiene direttamente all’oggetto.
class Producto {
#stock;
constructor(nombre, precio, stock) {
this.nombre = nombre;
this.precio = precio;
this.#stock = stock;
}
ajustarStock(cantidad) {
this.#stock += cantidad;
}
disponible() {
return this.#stock > 0;
}
}
const producto = new Producto("Taza", 12, 4);
producto.ajustarStock(-1);
console.log(producto.disponible()); // true
console.log(Object.hasOwn(producto, "nombre")); // true
La classe mantiene le scorte dietro una piccola interfaccia: per sapere se è rimasto un prodotto, il codice non deve leggere direttamente il campo. La verifica con Object.hasOwn() risponde a un’altra domanda: se nombre è definito in quell’istanza e non ereditato dal suo prototipo. Se provi ad accedere a producto.#stock dall’esterno della classe, il programma non viene compilato.
2. ES2023: ordinare una copia
sort() modifica l’array che riceve. In un’interfaccia che conserva lo stato precedente, questo effetto può essere indesiderato. toSorted() restituisce un altro array e lascia intatto l’elenco originale.
const productos = [
{ nombre: "Taza", precio: 12 },
{ nombre: "Cuaderno", precio: 8 },
{ nombre: "Lámpara", precio: 25 }
];
const porPrecio = productos.toSorted(
(a, b) => a.precio - b.precio
);
console.log(porPrecio.map(producto => producto.nombre));
// ["Cuaderno", "Taza", "Lámpara"]
console.log(productos.map(producto => producto.nombre));
// ["Taza", "Cuaderno", "Lámpara"]
Il comparatore numerico rende esplicito il criterio di ordinamento; senza di esso, sort() ordina in base alla conversione in testo. La stessa famiglia di ES2023 include toReversed(), toSpliced() e with(): operazioni che creano un nuovo risultato invece di modificare l’array di partenza. L’idea utile non è evitare sempre le mutazioni, ma sceglierle consapevolmente.
Raggruppare e trasformare collezioni
3. ES2024: passare da un elenco a gruppi
Supponiamo che una risposta di un’API sia già stata convertita in oggetti prodotto e che vogliamo mostrarli per categoria. Object.groupBy() riceve la collezione e una funzione che restituisce la chiave del gruppo.
const productos = [
{ nombre: "Manzana", categoria: "fruta" },
{ nombre: "Pera", categoria: "fruta" },
{ nombre: "Zanahoria", categoria: "verdura" }
];
const porCategoria = Object.groupBy(
productos,
producto => producto.categoria
);
console.log(porCategoria.fruta.map(producto => producto.nombre));
// ["Manzana", "Pera"]
console.log(porCategoria.verdura[0].nombre);
// "Zanahoria"
Il risultato raccoglie gli elementi in array in base alla chiave restituita dalla funzione. Per queste categorie, che sono stringhe, l’oggetto è un risultato pratico. ES2024 ha introdotto anche Map.groupBy(), utile quando si vogliono conservare chiavi che non sono stringhe, come valori booleani o oggetti. In entrambi i casi, il raggruppamento non elimina elementi: classifica quelli già presenti nell’input.
4. ES2025: concatenare operazioni sugli iteratori
Iterator Helpers consente di filtrare e trasformare gli elementi prima di materializzare il risultato. Questo esempio conserva i prodotti con prezzo inferiore a 20, converte ciascuno in un’etichetta e limita l’output a due elementi.
const productos = [
{ nombre: "Taza", precio: 12 },
{ nombre: "Cuaderno", precio: 8 },
{ nombre: "Lámpara", precio: 25 },
{ nombre: "Bolígrafo", precio: 3 }
];
const etiquetas = Iterator.from(productos)
.filter(producto => producto.precio < 20)
.map(producto => `${producto.nombre}: ${producto.precio} €`)
.take(2)
.toArray();
console.log(etiquetas);
// ["Taza: 12 €", "Cuaderno: 8 €"]
Iterator.from() adatta la collezione al flusso di operazioni; filter() e map() descrivono i passaggi, mentre take(2) limita il numero di risultati consumati. toArray() è il punto in cui si ottiene un array. A differenza della concatenazione di metodi degli array, gli helper lavorano con gli iteratori e possono rimandare l’esecuzione delle trasformazioni fino al consumo dei valori. Se l’ambiente non offre Iterator Helpers, questo blocco non funzionerà anche se gli altri esempi sì.
5. ES2026: raccogliere i valori da una sorgente asincrona
Una sorgente asincrona si consuma in modo diverso da un normale array. Array.fromAsync() permette di raccoglierne i valori in una collezione. Il generatore di questo esempio simula una sequenza che produce tre quantità.
async function* obtenerPrecios() {
yield 12;
yield 8;
yield 25;
}
const precios = await Array.fromAsync(obtenerPrecios());
const total = precios.reduce((suma, precio) => suma + precio, 0);
console.log(precios); // [12, 8, 25]
console.log(total); // 45
await attende il completamento della conversione; per questo l’esempio usa un file .mjs, in cui il livello superiore può includere await. La conversione raccoglie tutti i valori in memoria: è adatta quando serve l’intero array, ma non è un motivo per materializzare indiscriminatamente un flusso che potrebbe essere grande. La novità semplifica la conversione, ma non elimina il costo di memorizzare il risultato.
Errori comuni e uso nei progetti
Il primo errore è presumere che l’anno dello standard corrisponda a una versione specifica dell’ambiente. ECMAScript viene standardizzato e i motori adottano le funzionalità con i propri tempi. Prima di distribuire questi esempi, verifica la compatibilità nei browser o nelle versioni di Node.js che la tua applicazione deve supportare. Inoltre, MDN distingue il nucleo del linguaggio dalle API del browser: una funzione come fetch() appartiene alle API della piattaforma e non rende universale una funzionalità di ECMAScript.
Il secondo errore è confondere una copia con un aggiornamento dello stato. toSorted() restituisce un nuovo array; se il programma deve usarlo, salva e utilizza quel risultato. Il terzo è dimenticare che Object.groupBy() crea un raggruppamento basato sul valore restituito dalla funzione: anche una categoria scritta male crea un gruppo distinto. Con gli iteratori, ricorda che toArray() consuma il flusso e crea la collezione finale.
Questi strumenti non obbligano a riscrivere un’applicazione e non rendono moderno un programma da soli. Il loro valore consiste nel sostituire schemi ausiliari quando l’operazione necessaria corrisponde all’API: ordinare senza toccare l’originale, classificare un elenco o concatenare trasformazioni. Per una piccola collezione, un ciclo può continuare a essere perfettamente chiaro; per una base di codice condivisa, è importante che il team conosca il comportamento e il supporto del metodo scelto.
Il cambiamento di questi anni si nota nel lavoro quotidiano: più operazioni sulle collezioni sono disponibili direttamente nel linguaggio. Prova i blocchi nel motore di destinazione prima di integrarli; in particolare, verifica il supporto di Iterator.from() e Array.fromAsync().
Fonti: TecnoPS, Ecma International / TC39, MDN Web Docs, V8