ES10 news: una panoramica delle feature di ES2019
ES10 (es2019) news
Il comitato Ecma TC39, che è responsabile delle specifiche del nostro benamato ECMAScript, JavaScript per gli amici, ha da poco confermato la lista di feature che erano in stage 4. Questo significa che esse diventeranno parte delle specifiche di ES2019.
Con questo tweet Mathias Bynens ci conferma che non ci sono altre stage 4 proposals in attesa, perciò a quanto pare le features che elencheremo saranno quelle definitive per questa versione del linguaggio.
Quali novità sono state implementate quest’anno?
Array.prototype.{flat,flatMap}
Object.fromEntries
String.prototype.{trimStart,trimEnd}
Symbol.prototype.description
- Optional catch binding
Array.prototype.sort()
: obbligatoria un’implementazione stabileJSON.stringify
: revisione- JSON superset
Function.prototype.toString
: revisione
Vediamo di analizzarle una per una!
Array.prototype.flat
Motivo di gioia, assieme alla sua cugina flatMap, per tutti i functional programmers, ci permette di eseguire l’operazione flat su un array che contiene al suo interno uno o più array ad un qualsiasi livello di profondità.
Profondità che è impostata ad 1 di default, ma può essere modificata secondo la necessità in fase di chiamata del metodo:
const arr = [1, 2, [3, 4]]; arr.flat(); // [1, 2, 3, 4] const arr2 = [1, 2, [3, 4, [5, 6]]]; arr2.flat(); // [1, 2, 3, 4, [5, 6]] arr2.flat(1); // [1, 2, 3, 4, [5, 6]] arr2.flat(2); // [1, 2, 3, 4, 5, 6]
Array.prototype.flatMAP
È facile ricadere nella situazione in cui viene eseguita un’operazione di mapping su un array ed ogni singola trasformazione produce a sua volta un array, così che alla fine ci ritroviamo a dover gestire un array di array:
const admins = [ { name: 'Dario', aka: 'frongy', }, { name: 'Giacomo', aka: 'giac', }, { name: 'Paolo', aka: 'rizzo', }, { name: 'Andrea', aka: 'jfet', }, ]; // operazione di mapping che produce un array di array admins.map(admin => [admin.name, admin.aka]); /* [ ['Dario', 'frongy'], ['Giacomo', 'giac'], ['Paolo', 'rizzo'], ['Andrea', 'jfet'], ] */
Se volessimo anzi un array monodimensionale sul quale eseguire successive operazioni, possiamo sfruttare il metodo flatMap.
Questo metodo combina una operazione map con una un operazione flat di profondità 1.
Il metodo flatMap richiede infatti come argomento una mapper function:
// map + flat(1) admins.map(admin => [admin.name, admin.aka]).flat(1); /* [ 'Dario', 'frongy', 'Giacomo', 'giac', 'Paolo', 'rizzo', 'Andrea', 'jfet', ] */ // flatMap admins.flatMap(admin => [admin.name, admin.aka]); /* [ 'Dario', 'frongy', 'Giacomo', 'giac', 'Paolo', 'rizzo', 'Andrea', 'jfet', ] */
OBJECT.FROmENTRIES
Questa utility ci permette di creare un oggetto a partire da una lista di coppie chiave-valore.
Rinfreschiamoci un attimo la memoria e vediamo un paio di modi per ottenere una di queste liste:
1) Object.entries()
const obj = { prop: 'value', prop2: 42, } Object.entries(obj); /* [ ['prop', 'value'], ['prop2', 42], ] */
2) spread di una mappa
const map = new Map(); map.set('prop', 'value'); map.set('prop2', 42); [...map]; /* [ ['prop', 'value'], ['prop2', 42], ] */
L’utility Object.fromEntries può quindi essere considerata l’opposto di Object.entries:
const obj = { prop: 'value', prop2: 42, } const listOfKeyValuePairs = Object.entries(obj); Object.fromEntries(listOfKeyValuePairs); /* { prop: 'value', prop2: 42, } */
Qualche particolare in più:
• chiavi duplicate
// se una chiava compare più volte nella lista // viene sovrascritta Object.fromEntries( [ ['key', 42], ['key', 70]; ] ); /* { key:70 } */
• simboli usati come chiavi
Mentre il metodo Object.entries ignora le proprietà che possiedono come chiave un simbolo, l’utility Object.fromEntries ci permette di impostare uno o più simboli come chiave/i.
• COERCIZIONE DELLE chiavi
Gli unici tipi validi per le chiavi in un oggetto sono stringhe e simboli. Perciò se una coppia chiave-valore contenesse una chiave di altro tipo, essa verrà coercizzata in stringa.
• ITERABILi e oggetti array-like
Il metodo Object.fromEntries è molto flessibile. La lista di chiavi-valori non deve essere obbligatoriamente un array, ma può essere un qualsiasi iterabile. E la singola coppia chiave-valore non deve essere per forza un array, ma può essere un qualsiasi oggetto che possiede due proprietà aventi chiavi ‘0’ e ‘1’.
String.prototype.trimStart
String.prototype.trimEnd
Sicuramente avete utilizzato più di una volta il metodo trim su una stringa, che ci elimina eventuali whitespace presenti sia all’inizio che alla fine della stringa stessa:
" ciao ".trim(); // "ciao"
Adesso sarà possibile eseguire questa operazione solo su uno dei due estremi della stringa:
" ciao ".trimStart(); // "ciao " " ciao ".trimEnd(); // " ciao"
Symbol.prototype.description
Quando creiamo un simbolo, possiamo passare alla factory function un parametro di tipo stringa che verrà utilizzato come descrizione del simbolo:
const sym = Symbol('Descrizione');
Questa descrizione viene utilizzata quando si converte esplicitamente un simbolo in una stringa:
const sym = Symbol('Descrizione'); sym.toString(); // "Symbol('Descrizione')" String(sym); // "Symbol('Descrizione')"
Adesso è possibile accedervi direttamente tramite la read-only property description, la quale mostra direttamente la descrizione:
const sym = Symbol('Descrizione'); sym.description; // "Descrizione"
Optional catch binding
Questa feature ci permette di scrivere quanto segue:
try { // ... } catch { // ··· }
quando non siamo interessati ad utilizzare l’errore nel blocco catch.
Array.prototype.sort
Il metodo sort utilizzabile su un qualsiasi array è obbligato adesso ad utilizzare un’implementazione stabile. Il motore V8 che esegue il JavaScript su Chrome e Node utilizzava precedentemente una versione del QuickSort non stabile.
Adesso viene utilizzato il TimSort, che è un algoritmo stabile.
well-formed JSON.stringify
Una delle specifiche del formato JSON impone l’uso della codifica UTF-8 quando un testo in formato JSON viene scambiato con entità al di fuori del nostro ecosistema. Ad esempio un testo JSON utilizzato nella comunicazione client-server, dove due ecosistemi devono comunicare.
Prima di ES10 poteva accadere che il metodo stringify dell’oggetto JSON ritornasse sequenze di caratteri codificate con UTF-16.
JSON superset
Prima di ES10 il formato JSON non era un subset perfetto dell’EcmaScript. Le stringhe in JavaScript non potevano contenere caratteri come U+2028 LINE SEPARATOR e U+2029 PARAGRAPH SEPARATOR, costringendoci ad utilizzare sequenze di escape.
Invece le stringhe JSON potevano e possono contenere senza problemi quei caratteri.
Adesso la restrizione che creava il problema nelle stringhe JavaScript è stata rimossa.
Function.prototype.toString
L’output del metodo toString invocato su una funzione adesso può essere riassunto nel seguente modo:
- Ogni volta che è possibile verrà stampato il corpo della funzione. Perciò se una funzione è stata creata in JavaScript, il metodo dovrà restituirne il codice sorgente.
- Le funzioni che sono implementate direttamente dagli engine che eseguono il JavaScript produrranno un placeholder standardizzato. In particolare il corpo della funzione sarà
{ [native code] }
. Corpo che non potrà essere usato con certezza dalla funzione eval, né ora né con future versioni del linguaggio.
CONCLUSIONE
Rispetto ai precedenti anni non ci sono stati grandi stravolgimenti nella sintassi del linguaggio. Le uniche features degne di nota sono probabilmente i metodi flat e flatMap aggiunti agli array e l’utility Object.FromEntries.
Dalla versione 7.3 del motore V8 tutte queste features sono già utilizzabili in Chrome. Anche le ultime versioni di Firefox sembrano supportarle già tutte, perciò potete provare a giocarci un po’ da subito.
Approfondimenti
http://2ality.com/2018/02/ecmascript-2019.html
https://italiancoders.it/es10-news-una-panoramica-delle-features-di-es2019/