Lo standard di specifica del linguaggio ES6, spesso noto come ECMAScript 2015, è la sesta e più recente versione dello standard di specifica del linguaggio di scripting ECMAScript., allo scopo di garantire l’interoperabilità tra le implementazioni di vari browser e garantire il comune funzionamento. L’implementazione più conosciute di questo linguaggio (spesso definite come dialetti) è indubbiamente JavaScript. ES6 è molto più popolare dell’edizione ES5, in termini di definizione dello standard per l’implementazione di JavaScript. In questo articolo vedremo alcune delle funzionalità di ES6 che bisogna assolutamente conoscere per iniziare a programmare con Modern Javascript.
Javascript fu originariamente sviluppato da Brendan Eich alla fine degli anni 90 per il browser della Netscape Communications con il nome di Mochan e successivamente di LiveScript. In seguito è stato rinominato “JavaScript” ed è stato formalizzato con una sintassi più vicina a quella del linguaggio Java. Fu standardizzato per la prima volta il 1997 dalla ECMA (European Computer Manufacturers Association) con il nome ECMAScript. L’ultimo standard, di giugno 2021, è ECMA-262 Edition 12 ed è anche uno standard ISO (ISO/IEC 16262).
Differenze tra ES5 ed ES6
ES5 | ES6 |
---|---|
È stato introdotto nel 2009. | È stato introdotto nel 2015. |
Supporta tipi di dati primitivi che sono string, number, boolean, null, and undefined. | In ES6, ci sono alcune aggiunte ai tipi di dati JavaScript. Ha introdotto un nuovo tipo di dati primitivo “symbol” per supportare valori univoci. |
C’è solo un modo per definire le variabili usando la parola chiave var. | Esistono due nuovi modi per definire le variabili let e const. |
Ha prestazioni inferiori rispetto a ES6. | Ha prestazioni superiori a ES5. |
La manipolazione degli oggetti richiede molto tempo. | La manipolazione degli oggetti richiede meno tempo. |
In ES5, per definire una funzione vengono utilizzate sia la funzione che le parole chiave di ritorno. | Una funzione freccia è una nuova funzionalità introdotta in ES6 con la quale non è richiesta la parola chiave della funzione per definire la funzione. |
Fornisce una gamma più ampia di supporti della comunità rispetto a quella di ES6 | Fornisce una gamma inferiore di supporti della comunità rispetto a quella di ES5 |
Nuove funzionalità in ES6
Let e Const
E’ possibile definire variabili con il termine “let”, mentre si possono definire costanti con la parola chiave “const”. Prima di ES6, le variabili erano dichiarate con la sola parola chiave “var”, che aveva uno scope di funzione o globale (function-scoped or globally-scoped) a seconda di dove veniva dichiarata. Le variabili e le costanti “let”, d’altra parte, hanno uno scope di blocco (block-scoped), il che significa che possono essere utilizzate solo all’interno del blocco (di parentesi graffe) in cui sono dichiarate. Esempio di codice:
// dichiarazione variabili con var var x = 5; y = 8; var y; // la variabile può anche essere definita dopo l'assegnazione console.log(x); // 5 console.log(y); // 8 // dichiarazioni variabili con es6 let l = 4; c = 17; let c; //questo è un errore, in quanto non può essere definita dopo che è stata assegnata console.log(l); //4 console.log(c); // Error: Cannot access 'j' before initialization const m = 29; m = 39; console.log(k); // Error: Assignment to constant variable. let h; h = 'hello'; const n; n = 'goodbye'; // la costante n deve essere assegnata durante la dichiarazione, quindi tornerà un errore console.log(h); // hello console.log(n); // Error: Missing initializer in const declaration
Arrow Functions
Le Arrow Functions sono una nuova funzionalità di ES6. Hanno portato molta chiarezza e riduzione del codice poichè le parole chiave function e return vengono rimosse. Il risultato è una sintassi più compatta per la creazione di espressioni di funzione. Le Arrow Functions sono definite usando la questa notazione =>
// dichiarazione di funzione tradizionale
function foo(name) {
return 'Ciao' + name
}
// dichiarazione di funzione usando le arrow function
const foo = (name) => {
return 'Ciao ${name}';
}
// versione contratta di una arrow function senza l'uso di return
// se la funzione ha un solo parametro in ingresso, si possono eliminare le parentesi.
const foo = name => 'Ciao ${name}';
// altro esempio con due parametri in ingresso
let sum = (a, b) => a + b;
console.log(sum(90, 10)); // Output 100
Nell’ultima funzione definita, abbiamo eliminato le parole chiave function e return. Addirittura possiamo anche evitare la parentesi nello scenario in cui è presente un solo parametro, ma sarà sempre necessario includer () quando dobbiamo passare due o più parametri oppure quando non dobbiamo passare nessun parametro. Tuttavia, se il corpo della funzione contiene molte espressioni, dobbiamo racchiuderlo tra parentesi graffe (“{}”) e per restituire il valore richiesto, utilizzando la parola chiave return.
Template Literals e Multi-Line Strings
In ES6 vengono introdotti semplici modelli di stringhe e segnaposto per le variabili. Le stringhe vengono definite attraverso i simboli “ chiamati anche back-ticks. Al loro interno è possibile usare le classiche virgolette ” oppure richiamare variabili senza bisogno di concatenare le stringhe, utilizzando la sintassi ${PARAMETER}. Di seguito è riportato un esempio:
let esempio = `Il nome dell'utente è ${firstName} ${lastName}`
Utilizzando le virgolette back-ticks, è possibile formare una stringa multilinee senza bisogno di dover concatenare le stringhe, come veniva fatto su ES5. Ad esempio:
let multiriga =`
Ciao, io sono una stringa. io sono un'altra stringa. La variabile risulta quindi più leggibile.`
;
Parametri predefiniti
ES6 è possibile impostare parametri predefiniti. Se ad una funzione, non viene passato alcun valore o se viene passato undefined, è possibile impostare valori predefiniti per i parametri della funzione. Questa caratteristica non era presente su ES5, quindi era necessario implementare alcune righe di codice per controllare che le variabili non fossero undefined. Ecco l’esempio con ES6:
let somma = function(x = 20, y = 40) {
return x + y;
}
Javascript è un linguaggio Async. Questa caratteristica ci dà molta libertà quando scriviamo il codice perchè abbiamo in mano un’architettura non bloccante grazie alla quale possiamo scrivere facilmente codice non dipendente. Tuttavia, per la programmazione asincrona, JavaScript utilizzava le callback, che creava i noti problemi del callback hell o Pyramid of Doom, come mostrato nell’esempio qui sotto:
f1(function(x){ f2(x, function(y){ f3(y, function(z){ ... }); }); });
L’utilizzo di Promise in ES6 eviterà tutti i problemi associati alla callback. Innanzitutto scriviamo una funzione in ES5 con l’utilizzo di una callback:
function maggiore(a, b, callback) { var m = false; if(a > b) { m = true; } callback(m); } maggiore(1, 2, function(result) { if(result) { console.log('maggiore'); } else { console.log('minore') } })
Sopra abbiamo definito la funzione maggiore, che accetta tre argomenti a, b e callback. Quando viene eseguita, la funzione controlla se a è maggiore di b e imposta la variabile m = true, in caso contrario la variabile m = false. Dopodiché la funzione maggiore chiama la funzione di callback e passa la variabile m come argomento alla funzione. Quando usiamo la funzione maggiore, dobbiamo passare oltre ai due parametri, anche la funzione di callback anonima, che stabilisce se mostrare in console la stringa maggiore o minore a seconda se la variabile result sia true o false.
Vediamo adesso l’implementazione della funzione attraverso l’uso del Promise. Le promesse vengono impl
const maggiore = (a, b) => { return new Promise((resolve, reject) => { if(a > b) { resolve(true) } else { reject(false) } }) } maggiore(1, 2) .then(result => { console.log('maggiore') }) .catch(result => { console.log('minore') })
Come mostrato qui sopra, la funzione Promise può essere implementata come una arrow function. Attraverso i parametri resolve e reject, passiamo il valore booleano relativo al test di confronto tra le due variabili a e b. Quando dobbiamo usare la funzione, ogni volta che risolviamo una richiesta, verrà eseguito il blocco then e ogni volta che rifiutiamo una richiesta verrà eseguito il blocco catch.
Destructuring Assignment
Uno degli aspetti più popolari di ES6 è la destrutturazione. L’assegnazione di destrutturazione è un’espressione che consente di rimuovere rapidamente i valori dagli array o le proprietà dagli oggetti e archiviarli in variabili separate. È possibile destrutturare un array oppure un oggetto nei seguenti modi:
//Array Destructuring let user = ["giuseppe", "mario"]; let [a, b] = birds; // Array destructuring assignment console.log(a, b); //Object Destructuring let utente = {nome: "Mario", anni: 22}; let {nome, anni} = utente; // Object destructuring assignment console.log(nome, anni);
Moduli
I moduli sono una nuova funzionalità introdotta in ES6 che in precedenza non era supportata in maniera nativa in Javascript. Possiamo importare o esportare variabili, funzioni, classi o qualsiasi altro componente da/a diversi file e moduli utilizzando la dichiarazione “import” o “export”. Di seguito è riportato un esempio di codice:
//module.js export var num = 18; export function foo(fullName) { //data }; // main.js import {num, foo} from 'module'; console.log(num); // 18