Il mondo del web e dello sviluppo software ha visto la crescita esponenziale e la maturazione di JavaScript come uno dei linguaggi di programmazione più influenti e onnipresenti. Fin dai suoi umili inizi nei primi giorni del web, quando era usato principalmente per aggiungere interattività di base alle pagine web, JavaScript ha percorso una strada lunga e tortuosa. Ora, è al centro delle applicazioni web moderne, delle tecnologie di sviluppo Front-End e perfino degli ambienti di Back-End con piattaforme come Node.js.
L’emergere di ogni nuova versione di ECMAScript, la specifica ufficiale dietro JavaScript, segna un ulteriore passo nella sua evoluzione. Con l’arrivo di ECMAScript 2023 (ES14), il linguaggio introduce nuovi strumenti e funzionalità, consolidando ulteriormente la sua posizione come colonna portante della tecnologia web moderna. Anche se ES14 non ha portato una rivoluzione completa, i suoi aggiornamenti e perfezionamenti offrono nuove opportunità e soluzioni per gli sviluppatori di tutto il mondo.
Proseguiamo ora con una panoramica più dettagliata di ciò che ES14 ha da offrire e di come queste novità influenzeranno il panorama dello sviluppo in JavaScript.
Introduzione alle Specifiche ECMAScript
Le specifiche ECMAScript fungono da bibbia per JavaScript. Forniscono una documentazione dettagliata delle funzionalità del linguaggio, servendo sia come riferimento educativo per gli sviluppatori sia come guida per gli implementatori di motori JavaScript.
Per chi è nuovo a queste specifiche, è possibile esplorarle sul sito ufficiale tc39.es/ecma262/. Le specifiche per il 2023 sono disponibili su tc39.es/ecma262/2023/. Questo documento, oltre ad essere una miniera d’oro di informazioni, riflette l’adattabilità e la resilienza di JavaScript come linguaggio, crescendo e evolvendosi in risposta alle esigenze reali degli sviluppatori.
Uno degli aspetti interessanti delle specifiche ECMAScript è la loro natura evolutiva. Non sono statiche. Cambiano, si adattano e crescono in risposta alle esigenze degli sviluppatori e ai progressi tecnologici nel campo del web e dello sviluppo software. Spesso, vediamo che una nuova funzionalità diventa parte delle specifiche ufficiali solo dopo essere stata accettata e adottata dalla comunità degli sviluppatori. Questo dimostra la natura dinamica e reattiva del processo di sviluppo delle specifiche.
Prendiamo ad esempio la sintassi Shebang introdotta in ES14. Questa non è una funzionalità completamente nuova per la comunità degli sviluppatori. Era già utilizzata in alcuni contesti, ma ora, con la sua inclusione nelle specifiche, diventa una parte standardizzata del linguaggio. Una volta che una funzionalità è stata codificata nelle specifiche, funge da base stabile per ulteriori innovazioni e adattamenti.
Alcune delle funzionalità introdotte nelle specifiche ECMAScript nel corso degli anni sono state influenzate da altri linguaggi di programmazione. Ad esempio, l’introduzione della sintassi async/await è stata influenzata dal linguaggio C#. Questo dimostra che le specifiche ECMAScript non sono solo un set insulare di regole, ma piuttosto un documento vivo che impara e si adatta prendendo ispirazione da varie fonti.
Lettura consigliata: La Dev Mode di Figma: cos’è e come funziona
Il ruolo delle specifiche nella crescita di JavaScript
Una parte cruciale dello sviluppo di JavaScript è il modo in cui le specifiche ECMAScript hanno accompagnato e guidato la sua evoluzione. Da semplici script per creare effetti hover su immagini a potenti applicazioni web a singola pagina (SPA), JavaScript si è evoluto a passi da gigante. E le specifiche ECMAScript hanno avuto un ruolo fondamentale in questa trasformazione.
Uno dei principi cardine delle specifiche ECMAScript è la loro capacità di riflettere la realtà pratica. Molte volte, una funzionalità viene integrata nelle specifiche ufficiali solo dopo essere stata ampiamente adottata e accettata dalla comunità. Questo approccio bottom-up garantisce che le nuove aggiunte siano realmente utili e rispondano alle esigenze attuali.
Ora diamo un’occhiata alle nuove funzionalità introdotte in JavaScript nel 2023.
Cambiare gli array “per copia”: immutabilità, funzioni pure ed effetti collaterali
La manipolazione degli array è un aspetto fondamentale della programmazione JavaScript. ECMAScript 2023 introduce metodi di array avanzati che ci consentono di apportare modifiche a un array mantenendo invariato l’array originale. Invece di modificare direttamente l’array (tramite le cosiddette funzioni “in-place” o “in loco”), questi metodi creano una nuova copia dell’array con le modifiche desiderate. Queste funzioni vengono chiamate “pure”, dato che non modificano lo stato dei loro parametri, ma restituiscono un nuovo oggetto che rappresenta il risultato della chiamata alla funzione. Nelle funzioni pure possiamo manipolare con sicurezza i valori dell’array senza preoccuparci degli “effetti collaterali” indesiderati sull’array originale, che mantiene la sua immutabilità.
Questa strategia è molto utile nelle applicazioni moderne basate sulla programmazione funzionale e dichiarativa.
Questa caratteristica è molto importante, perché aiuta a mantenere l’integrità dell’array originale consentendoci comunque di lavorare con versioni modificate quando necessario.
Andiamo ad analizzare questi nuovi metodi che vengono aggiunti a Array.prototype e TypedArray.prototype.
Lettura consigliata: React, tutto sulla libreria Javascript
toSorted()
toSorted ha la stessa firma di Array.prototype.sort(), ma crea un nuovo array invece di operare sull’array stesso.
const numbers = [5,4,2,3,1]
numbers === numbers.sort() // true - [1, 2, 3, 4, 5]
numbers === numbers.toSorted() // false - [1, 2, 3, 4, 5]
Code language: JavaScript (javascript)
La prima chiamata a sort modifica l’array numbers.
La seconda chiamata a toSorted genera un nuovo array e lo restituisce.
toSorted(), come sort(), accetta anche un singolo argomento opzionale, una funzione comparatrice. Ad esempio, potremmo utilizzare toSorted() per creare un nuovo array in ordine decrescente:
const numbers = [10, 5, 2, 7, 3, 9, 1, 6, 4]
const sortedNumbers = numbers.toSorted((n1, n2) => {
return n2 - n1;
})
// [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
console.log(sortedNumbers)
Code language: JavaScript (javascript)
Anche toSorted() può essere applicato ad array di oggetti. In questo caso devi fornire una funzione comparatrice che utilizzi direttamente i dati degli oggetti, dato che non esiste un ordinamento naturale per gli oggetti:
const objs = [{ name: "Anna", age: 30 }, { name: "Mario", age: 25 }, { name: "Luigi", age: 40 }, { name: "Lisa", age: 20 }];
const sortedObjs = objects.toSorted((o1, o2) => {
return o1.name.localeCompare(02.name)
})
//[{"name":"Luigi","age":40},{"name":"Mario","age":25},{"name":"Anna","age":30},{"name":"Lisa","age":20}]
console.log(sortedObjs)
Code language: JavaScript (javascript)
toReversed()
Come toSorted() per sort(), toReversed() è il cugino di reverse().
const months = ['January', 'February', 'March', 'April', 'May']
// reverse(), l'array originale viene alterato
const reversedMonths = months.reverse()
console.log(months) => ['May', 'April', 'March', 'February', 'January']
console.log(reversedMonths) => ['May', 'April', 'March', 'February', 'January']
// toReversed(), l'array originale rimane inalterato
const reversedMonths = months.toReversed()
console.log(months) => ['January', 'February', 'March', 'April', 'May']
console.log(reversedMonths) => ['May', 'April', 'March', 'February', 'January']
Code language: JavaScript (javascript)
toSpliced()
Come toSorted() per sort(), e toReversed() per reverese(). toSpliced() è il cugino di splice().
Quando si utilizza toSpliced, viene restituito un nuovo array, che riflette le modifiche desiderate, mentre splice restituisce un array contenente i valori rimossi.
Questa distinzione rende toSpliced una scelta utile quando è importante preservare l’array originale e quando si preferisce un approccio non distruttivo.
Utilizzando toSpliced possiamo manipolare in modo sicuro gli array senza preoccuparci di modifiche involontarie ai dati originali, migliorando l’affidabilità e la manutenibilità del codice.
const colors = ["red", "orange", "yellow", "green", "blue", "purple"]
// ["red", "orange", "pink", "cyan", "green", "blue", "purple"]
const newColors = arr.toSpliced(2, 1, "pink", "cyan")
// ‘green’
console.log(colors[3])
// 'cyan'
console.log(newColors[3])
Code language: JavaScript (javascript)
A differenza dei metodi precedenti, toSpliced() esiste unicamente per Array.prototype.
with()
L’aggiornamento degli elementi all’interno di un array è un’operazione comune in JavaScript. Tuttavia, la modifica diretta degli elementi dell’array può portare a effetti collaterali indesiderati. Il metodo with(), introdotto in ECMAScript 2023, offre un modo sicuro per aggiornare gli elementi in un array senza alterare l’array originale.
Immaginiamo di avere un array di nomi utente e di voler aggiornare un nome utente specifico senza alterare l’array originale:
const usernames = ['Mario', 'Luigi', 'Anna']
// vecchia modalità di aggiornamento
usernames[1] = 'Peach'
console.log(usernames) // ['Mario', 'Peaach', 'Anna']
// using with(), l'array originale rimane inalterato
const updatedUsernames = usernames.with(1, 'Peach')
console.log(usernames) => ['Mario', 'Luigi', 'Anna']
console.log(updatedUsernames) // ['Mario', 'Peach', 'Anna']
Code language: JavaScript (javascript)
Array e ricerche
Lavorare con gli array spesso implica la ricerca di elementi specifici. Il metodo find è stato introdotto per semplificare questo processo, ma restituisce solo il primo elemento corrispondente ad un criterio di ricerca. Tuttavia, alcuni scenari richiedono di cercare dalla fine dell’array per trovare l’ultimo elemento corrispondente. È qui che entrano in gioco i nuovi metodi findLast e findLastIndex.
Esistono scenari in cui la ricerca dall’ultimo elemento è più pratica:
Registri basati sul tempo: immagina una serie di voci di registro ordinate per timestamp. Se vogliamo trovare l’ultima voce di registro di un utente specifico, la ricerca dalla fine garantisce di ottenere la voce più recente.
Coda con priorità inversa: in alcuni casi, potremmo mantenere una coda con priorità in cui gli elementi più recenti hanno una priorità più alta. Quando si recuperano elementi con la massima priorità, la ricerca dall’ultimo elemento garantisce di ottenere l’ultimo elemento con alta priorità.
findLast()
Il metodo findLast() ti consente di ottenere l’istanza finale di un elemento corrispondente da un array. Se non viene trovato alcun elemento corrispondente, restituisce undefined. Nell’esempio seguente vediamo come trovare l’ultimo numero pari dell’array:
const numbers = [17, 5, 87, 14, 100, 11];
const lastEven = numbers.findLast((number) => {
return number % 2 === 0
})
console.log(lastEven) // 100
Code language: JavaScript (javascript)
findLast() supporta anche il passaggio di un “thisArg” per impostare il contesto del this nella funzione.
findLastIndex()
Allo stesso modo, il metodo findLastIndex() può essere utile quando dobbiamo trovare l’indice dell’ultimo elemento che soddisfa una condizione. Nell’esempio seguente vediamo come trovare l’ultimo numero dell’array divisibile per 10:
const numbers = [17, 5, 87, 14, 100, 11];
numbers.findLastIndex(number => number % 10 === 0); // 100
Code language: JavaScript (javascript)
Supporto per lo la grammatica Hashbang (notazione shebang)
L’introduzione della Hashbang Grammar in ECMAScript 2023 ci consente di utilizzare la notazione shebang (#!) nel codice sorgente. Questa funzionalità semplifica la distinzione tra script e moduli e fornisce una migliore compatibilità con gli strumenti di creazione e rende Javascript coerente con altri linguaggi.
Uno shebang è una notazione Unix vecchia scuola costituito un hashtag seguito da un punto esclamativo: #! (dove “bang” è slang per “!”). Da tempo immemorabile, un commento all’inizio di un file che inizia con #! dice alla shell che si tratta di uno script eseguibile e quale motore usare per eseguirlo.
#!/usr/bin/env node
console.log("Hello, world!")
Code language: JavaScript (javascript)
Questo script dice al sistema operativo di utilizzare Node per eseguire questo script. Ora puoi semplicemente digitare ./hello.js per eseguirlo.
Simboli come chiavi delle WeakMap: un passo avanti nella gestione della memoria
Una delle caratteristiche principali introdotte in ES14 è l’espansione di ciò che può essere utilizzato come chiavi nelle WeakMap. Ma prima di addentrarci nelle novità, facciamo un passo indietro e comprendiamo cosa sono le WeakMap.
In programmazione, un riferimento debole è un tipo di riferimento che può essere eliminato dalla garbage collection, al contrario di un riferimento forte. Questa caratteristica è particolarmente utile in certi scenari per prevenire perdite di memoria.
Prima di ES14, solo gli oggetti potevano essere utilizzati come chiavi in raccolte come WeakMap. Tuttavia, con l’introduzione delle nuove specifiche, ora è possibile utilizzare la maggior parte dei simboli come chiavi.
const weakMap = new WeakMap();
const keySymbol = Symbol('key');
weakMap.set(keySymbol, 'value');
// Da qualche parte nel codice, perdiamo il riferimento a keySymbol
// La garbage collection riconoscerà che non ci sono più riferimenti a keySymbol
// e pulirà automaticamente la voce corrispondente nel WeakMap.
Code language: JavaScript (javascript)
Questa nuance sembra minore, ma ha profonde implicazioni sulla gestione della memoria e sulla prevenzione delle perdite di memoria. La capacità di utilizzare simboli come chiavi amplia le possibilità per gli sviluppatori e offre una flessibilità senza precedenti nella gestione delle WeakMap.
Conclusione e sguardo al futuro
Sebbene il 2023 non abbia portato cambiamenti rivoluzionari in JavaScript, ECMAScript 2023 (ES14) ha consolidato ulteriormente il linguaggio, rendendolo ancora più potente, flessibile e adattabile alle esigenze contemporanee. Con l’evoluzione continua del web e l’importanza sempre maggiore di JavaScript nel panorama della programmazione, possiamo aspettarci che le future versioni del linguaggio portino ancora più innovazioni e miglioramenti. E con l’attesa di nuove funzionalità, come l’API temporale per la gestione dei datetime (Temporal), il futuro di JavaScript sembra più luminoso che mai.