ES6 è stata una rivoluzione nel mondo JavaScript ed ha portato il linguaggio ad uno step successivo.
In questo talk si affrontano gli aspetti che hanno resto fondamentale questo nuovo standard.
10. CrossDevice
Web Browser
Desktop
Mobile: phone e tablet
TV / LFD / Walls
Wearable
Totem / Kiosk
IoT
Isomorfo
CrossPlatform
Windows
OS X
Linux
Android
iOS
Windows Phone
Chromium
WEB / HYBRID applications
Javascript
10
11. Terminologia
JavaScript Il nome del linguaggio
o meglio un'implementazione dello standard
ECMAScript Lo standard del linguaggio
TC 39 La commissione tecnica
(nel passato abbastanza turbolenta!)
ECMAScript Harmony Il nome in codice migliorie post ES5
un modo per dirsi...volemose bene!
ECMAScript.Next Il nome in codice per le release
successive
ECMAScript20XX/ESX Le release rilasciate
11
12. Breve Storia di JS
1995 Mocha
1996 Standardizzazione ECMA
1997 ECMA-262 (ES1)
1998 ES2
1999 ES3
2008 ES4 (abbandonato)
2009 ES5 (prima 3.1)
2015 ECMASCRIPT2015/ES6
201x ECMASCRIPT201x/ESx+1
12
15. Corregge alcuni dei problemi
più comuni di ES5
Compatibilità verso il passato
(pensiamolo come un superset di ES5)
Sintassi Moderna
(evitiamo battute!)
Pronto per le applicazioni
complesse e scalabili
Tante nuove funzionalità nella
libreria standard
15
17. ES6 aggiorna la lingua senza breacking changes.
L'approccio adottato è chiamato One JavaScript
Il cui principio è: “don’t break the web”.
Molte delle funzionalità di ES6 è già supportata negli engine
attuali, ma non tutte e quindi...
...per usare ES6 è richiesto l'uso di transpiler/compiler: Babel,
Traceur, Typescript compiler, ...
Tabella di compatibilità
17
19. Modules
Classes
Decorators (ES7)
Promises
Interators e generators
Multi-line Strings
Destructuring Assignment
Arrow Functions
Default Parameters
Enhancements in Object and
Array
Block-Scoped Constructs
let e const
Caratteristiche
19
20. Costanti e Variabili
ES6 fornisce due modi nuovi per dichiarare variabili:
let e const, che sostituiscono prevalentemente il modo
ES5 di dichiarare variabili, var.
20 . 1
21. Scope
Lo scope è il contesto corrente del codice, e gli ambiti
possono essere definiti globalmente o localmente.
20 . 2
22. Scope
Prima di scrivere una linea di JavaScript siamo nel Global Scope
Ogni funzione definita in un'altra funzione ha un ambito locale
collegato alla funzione esterna
Nuove funzioni = Nuovo scope
Lexical scope. Ogni variables/objects/functions definite nel
parent scope, sono disponibili nello scope chain
ma non viceversa
Quando si risolve una variabile, JavaScript inizia dallo scope più
interno verso l'esterno finché non la trova
20 . 3
23. Hoisting
L'Hoisting è un meccanismo JavaScript per cui le
variabili e le dichiarazioni di funzione vengono spostate
in cima al loro ambito prima dell'esecuzione del codice.
20 . 4
25. HOISTINGHOISTING
function test() {
foo(); // TypeError "foo is not a function"
bar(); // "questa va bene!"
var foo = function () { // function expression to local var 'foo'
alert("non va bene!");
}
function bar() { // function declaration 'bar'
alert("questa va bene!");
}
}
test();
20 . 6
26. let / const
let La variabile che dichiara è block-scoped, quindi esiste
solo all'interno del blocco corrente.
var è function-scoped.
const Funziona come let, ma la variabile da dichiarare deve
essere immediatamente inizializzata, con un valore che
non può essere modificato
20 . 7
27. Costanti e Variabili
Hoisting Scope Creates global
properties
var Declaration Function Yes
let Temporal dead
zone
Block No
const Temporal dead
zone
Block No
function Complete Block Yes
class No Block No
import Complete Module-
global
No
20 . 8
28. Let
let permette di dichiarare variabili limitandone la
visibilità ad un blocco di codice, ad un assegnazione, ad
un espressione in cui è usata.
La parola chiave var invece definisce una variabile
globalmente in uno script o localmente in un qualunque
blocco di codice di una funzione.
20 . 9
29. LETLET
var a = 5;
var b = 10;
if (a === 5) {
let a = 4; // Lo scope è block-level
var b = 1; // Lo scope è function-level
console.log(a); // 4
console.log(b); // 1
}
console.log(a); // 5
console.log(b); // 1
20 . 10
30. LETLET
for (let i = 0; i<10; i++) {
alert(i); // 1, 2, 3, 4 ... 9
}
alert(i); // i non è definita
20 . 11
31. Const
Le costanti (create quindi con const) sono immutabili.
non è possibile assegnare loro valori diversi
La dichiarazione const crea un riferimento di sola lettura a un valore.
Non significa che il valore che detiene è immutabile, solo che l'identificatore della variabile non
può essere riassegnato.
Le variabili dichiarate con const vanno inizializzate
20 . 12
32. CONSTCONST
//Le costanti possono essere dichiarate sia in maiuscolo che in minuscolo,
//ma la convezione suggerisce il maiuscolo.
const MY_FAV = 7; // Definisco la costante ed assegno il valore
MY_FAV = 20; // questa istruzione provocherà un errore
// questa istruzione stamperà il valore 7
console.log('my favorite number is: ' + MY_FAV);
const MY_FAV = 20; //provare a ridichiarare una costante provoca un errore
// e non può essere riutilizzata in altri tipi di dichiarazione
var MY_FAV = 20;
let MY_FAV = 20;
20 . 13
33. CONSTCONST
const FOO; // Errore manca l'inizializzatore
// const lavora anche con gli objects
const MY_OBJECT = {'key': 'value'};
MY_OBJECT = {'OTHER_KEY': 'value'}; //errore
// Tuttavia, le chiavi oggetto non sono protette
// e quindi viene eseguita la seguente istruzione senza problemi
// Usa Object.freeze() per rendere l'oggetto immutabile
MY_OBJECT.key = 'otherValue';
// const lavora anche con gli array
const MY_ARRAY = [];
// è possibile aggiungere elementi all'array
MY_ARRAY.push('A'); // ["A"]
// ma assegnare un nuovo array provocherebbe errore
MY_ARRAY = ['B']
20 . 14
34. BLOCK-SCOPINGBLOCK-SCOPING
// È importante notare la natura del block-scoping
if (MY_FAV === 7) {
// questo va bene e crea una variabile MY_FAV a livello di blocco
let MY_FAV = 20;
// MY_FAV è adesso 20
console.log('my favorite number is ' + MY_FAV);
// ma questa operazione sposta nel global-context (via hoisting)
//e provocherà errore
var MY_FAV = 20;
}
// MY_FAV è ancora 7
console.log('my favorite number is ' + MY_FAV);
20 . 15
35. Temporal Dead Zone
Il tempo tra l'inizio del blocco e la dichiarazione è
chiamata TDZ.
Una variabile dichiarata da let o const ha una cosiddetta zona morta temporale (TDZ):
Quando si entra nel campo di applicazione, non è possibile accedere (get o set) finché l'esecuzione non raggiunge la
dichiarazione.
let e const non sono soggetti al Variable Hoisting,
difatti riferendo la variabile nel blocco prima
dell'inizializzazione si ottiene un ReferenceError.
20 . 16
36. TDZTDZ
let tmp = true;
if (true) { // entra in un nuovo scope, TDZ inizia
// Viene creato un binding non ancora inizializzato per `tmp`
console.log(tmp); // ReferenceError
let tmp; // TDZ si conclude, `tmp`è inizializzato con `undefined`
console.log(tmp); // undefined
tmp = 123;
console.log(tmp); // 123
}
console.log(tmp); // true
// La TDZ finisce dopo che l'inizializzazione
// è stata valutata ed assegnata alla variabile
let foo = console.log(foo); // ReferenceError
20 . 17
37. Let / Const in loop heads
In For Loop var binda singolarmente il valore, mentre
let redichiara la variabile.
In For-of e For-in, var binda singolarmente il valore,
mentre let e const redichiara la variabile.
20 . 18
38. FORFOR
const arr = [];
for (var i=0; i < 3; i++) {
arr.push(() => i);
}
arr.map(x => x()); // [3,3,3]
const arr = [];
for (let i=0; i < 3; i++) {
arr.push(() => i);
}
arr.map(x => x()); // [0,1,2]
// TypeError: assegnazione ad una costante (a causa di i++)
for (const i=0; i<3; i++) {
console.log(i);
}
20 . 19
39. FOR-OF / FOR-INFOR-OF / FOR-IN
const arr = [];
for (var i of [0, 1, 2]) {
arr.push(() => i);
}
arr.map(x => x()); // [2,2,2]
const arr = [];
for (const i of [0, 1, 2]) {
arr.push(() => i);
}
arr.map(x => x()); // [0,1,2]
20 . 20
40. Quindi che uso?
const Ogni volta che una variabile non cambia mai il suo
valore. (Anche nei loop)
È possibile modificare un oggetto che si riferisce a una variabile const
let Ogni volta che il valore iniziale di una variabile cambia in
seguito
var Dimenticala! (finchè si può!)
20 . 21
42. Template literals
Template
literals
sono stringhe che possono estendersi su più righe
(via backtick) e includere espressioni interpolate (via
${···})
Tagged
template
literals
Una forma più avanzata di costrutto con le quali è
possibile modificare l'output delle template literals
usando una funzione.
21 . 2
43. TEMPLATE LITERALSTEMPLATE LITERALS
const firstName = 'Jane';
console.log(`Hello ${firstName}!
it's ${new Date()}
The sum is ${10 + 3}
How are you today?`);
// Output:
// Hello Jane!
// it's Wed Jul 26 2017 13:13:20 GMT+0200 (CEST)
// The sum is 13
// How are you today?
21 . 3
44. TAGGED TEMPLATE LITERALSTAGGED TEMPLATE LITERALS
var a = 5;
var b = 10;
function tag(strings, ...values) {
console.log(strings[0]); // "Hello "
console.log(strings[1]); // " world "
console.log(values[0]); // 15
console.log(values[1]); // 50
}
tag`Hello ${ a + b } world ${ a * b }`;
//Output:
// Hello
// world
//15
//50
21 . 4
45. Enhanced Object Literals
Object literal è una lista di coppie chiave/valore suddivisi
da virgola e racchiuso tra {}
ES6 ha aggiunto molto zucchero sintattico
Method definitions
Property value shorthands
Computed property keys
22 . 1
46. METHOD DEFINITIONSMETHOD DEFINITIONS
//ES6
obj = {
foo (a, b) { … },
bar (x, y) { … },
*quux (x, y) { … }
};
//ES5
obj = {
foo: function (a, b) { … },
bar: function (x, y) { … }
// quux: nessun equivalente su ES5
};
//ES5/ES6
obj = {
get foo() { … },
set bar(value) { … }
};
22 . 2
47. PROPERTY VALUE SHORTHANDSPROPERTY VALUE SHORTHANDS
Se il nome della variabile che specifica il valore della
proprietà è uguale chiave di proprietà, è possibile
omettere la chiave.
const x = 4;
const y = 1;
const obj = { x: x, y: y };
const obj = { x, y };
function getCar(make, model, value) {
return {
make,
model,
_value: value
};
}
22 . 3
48. COMPUTED PROPERTY KEYSCOMPUTED PROPERTY KEYS
Due strade per specificare la chiave di una
proprietà/funzione: via fixed name e via expression
const propKey = 'foo';
const obj = {
[propKey]: true,
['b'+'ar']: 123
};
console.log(obj.foo); // true
const obj = {
['h'+'ello']() {
return 'hi';
}
};
console.log(obj.hello()); // hi
22 . 4
49. COMPUTED PROPERTY KEYSCOMPUTED PROPERTY KEYS
function getCar(make, model, value) {
return {
// i computed values lavorano anche con
// object literals
['make' + make]: true
};
}
let car = getCar('Kia','Sorento', 10);
console.log(car); // { makeKia: true }
22 . 5
50. Destructuring
Un modo comodo e conveniente per estrarre valori da
array o oggetti in variabili distinte.
Object destructuring
Array destructuring
23 . 1
53. Le basi
Nel destructuring sono coinvolte due entità:
Destructuring
Source
I dati da destrutturare. Ad esempio, il valore di
un'assegnazione di destrutturazione.
Destructuring
Target
Il modello utilizzato per il destructuring. Ad
esempio, le variabili di un'assegnazione di
destructuring.
23 . 4
54. In ES6 abbiamo la possibilità di destrutturare il target,
utilizzando la source.
Nell'assegnazione la chiave è il source
ed il value il target
let a = {x: 1, y: 2};
let {x:x, y:z} = a;
console.log(x) // 1
console.log(z) // 2
let {y} = a;
console.log(y) // 2
23 . 5
55. ARRAY DESTRUCTURINGARRAY DESTRUCTURING
// Assegnazione semplice di variabile
let x = [1, 2, 3, 4, 5];
let [y, z] = x;
console.log(y); // 1
console.log(z); // 2
// Assegnazione separata dalla dichiarazione
let a, b;
[a, b] = [1, 2];
console.log(a); // 1
console.log(b); // 2
23 . 6
57. ARRAY DESTRUCTURINGARRAY DESTRUCTURING
Destructuring di un array ritornato da una funzione
function f() {
return [1, 2];
}
let a, b;
[a, b] = f(); // puoi fare questo grazie alla destrutturazione
// invece di questo
a = f()[0];
b = f()[1];
// è la stessa identica cosa, però c'è un enorme differenza
//in termini di leggibilità
console.log(a); // 1
console.log(b); // 2
23 . 8
58. ARRAY DESTRUCTURINGARRAY DESTRUCTURING
Destructuring di un array ritornato da una funzione
//Ignorare alcuni valori ritornati
function f() {
return [1, 2, 3];
}
let [a, , b] = f();
console.log(a); // 1
console.log(b); // 3
23 . 9
60. OBJECT DESTRUCTURINGOBJECT DESTRUCTURING
Assegnazione semplice di variabile
var o = {p: 42, q: true};
var {p, q} = o;
console.log(p); // 42
console.log(q); // true
// Assegnazione senza dichiarazione
var a, b;
({a, b} = {a:1, b:2});
23 . 11
61. DEFAULT VALUEDEFAULT VALUE
// Default Value è usato se il match sul source è undefined (o mancante).
let [a,b = 3, c = 7] = [1, undefined]; // a === 1, b === 3, c === 7
let {x = 1, y = 2, z = 3} = {x: undefined, z: 7}
// x === 1, y === 2, z === 7
// Inoltre sono valutati lazily
function con() {
console.log('test');
return 10;
}
let [x = con()] = [];
//x === 10 con 'test' su console
let [x = con()] = [5];
// x === 5
23 . 12
62. L'operatore Rest
Elision
// Consente di estarre i valori rimanenti in un array
let [a,b,...z] = [1, 2, 3, 4, 5, 6];
// Rest Operator - a === 1, b === 2, z === [3,4,5,6]
// Consente di utilizzare la sintassi _Array Holes_
// per saltare gli elementi durante la distruzione
let [,, ...z] = [1, 2, 3, 4, 5, 6];
// Elision - z === [3,4,5,6]
23 . 13
64. Iterazione con for...of e destrutturazione
var people = [{
name: "Mike Smith",
family: { mother: "Jane Smith",
father: "Harry Smith",
sister: "Samantha Smith" },
age: 35
},{
name: "Tom Jones",
family: { mother: "Norah Jones",
father: "Richard Jones",
brother: "Howard Jones" },
age: 25
}];
for (var {name: n, family: { father: f } } of people) {
console.log("Name: " + n + ", Father: " + f);
}
// "Name: Mike Smith, Father: Harry Smith"
// "Name: Tom Jones, Father: Richard Jones"
23 . 15
65. Estrarre campi dagli oggetti passati
come parametri di funzioni
function userId({id}) {
return id;
}
function whois({displayName: displayName, fullName: {firstName: name}}){
console.log(displayName + " is " + name);
}
var user = {
id: 42,
displayName: "jdoe",
fullName: { firstName: "John",
lastName: "Doe"}
};
console.log("userId: " + userId(user)); // "userId: 42"
whois(user); // "jdoe is John"
23 . 16
66. Arrow Funcion
Una funzione a freccia ha una sintassi più compatta rispetto alla
notazione a funzione
Usa il lexical scope nell'utilizzo della parola chiave this
Sono sempre anonime.
È maggiormente indicata per le funzioni piuttosto che
con i metodi
Non possono essere usate come costruttori
Non è solo quindi zucchero sintattico
24 . 1
67. ARROW FUNCTIONARROW FUNCTION
function inc(x) {
return x + 1;
}
let inc = x => x + 1;
let inc = (x, y) => x + y;
let inc = () => 10;
let inc = (x) => {
console.log(x);
return x + 1;
}
24 . 2
68. ARROW FUNCTIONARROW FUNCTION
(param1, param2, …, paramN) => { statements }
(param1, param2, …, paramN) => expression
// equivalente a: (param1, param2, …, paramN) => { return expression; }
// Le Parentesi sono opzionali se è presente un solo parametro:
(singleParam) => { statements }
singleParam => { statements }
// Una funzione senza parametri richiede comunque le parentesi:
() => { statements }
() => expression // equivalente a: () => { return expression; }
// Il body tra parentesi indica la restituzione di un oggetto:
params => ({foo: bar})
24 . 3
69. ARROW FUNCTIONARROW FUNCTION
// Sono supportati ...rest e i parametri di default
(param1, param2, ...rest) => { statements }
(param1 = defaultValue1, param2, …, paramN = defaultValueN) => {
statements
}
// Si può anche destrutturare all'interno della lista dei parametri
let f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
f(); // 6
24 . 4
70. Arrow Funcion - this
this context
Window Object, global scope
Object literals / Constructors
Dynamics (per esempio per gli events)
Lexical Scope
24 . 5
71. Arrow Funcion - this
Lexical scope.
Ogni variables/objects/functions definite nel parent
scope, sono disponibili nello scope chain
ma non viceversa
Prima delle arrow function, ogni nuova funzione definiva il proprio this
Una arrow function invece non crea il proprio this, e
quindi this mantiene il significato che aveva all'interno
dello scope genitore.
24 . 6
72. In ECMAScript 3/5, questo problema veniva aggirato
assegnando il valore this a una variabile.
function Person() {
var that = this;
that.age = 0;
setInterval(function growUp() {
that.age++;
}, 1000);
}
24 . 7
73. Una arrow function invece non crea il proprio this
function Person(){
this.age = 0;
setInterval(() => {
this.age++; // this si riferisce alla proprietà dell'oggetto
}, 1000);
}
var p = new Person();
24 . 8
74. Altri casi
// Una funzione a freccie vuota restituisce undefined
let empty = () => {};
(() => "foobar")() // IIAF, restituisce "foobar"
// Singolo parametro senza ()
let simple = a => a > 15 ? 15 : a;
simple(16); // 15
simple(10); // 10
// Parametri Multipli con ()
let max = (a, b) => a > b ? a : b;
24 . 9
75. Altri casi
// Più semplice gestire filtering, mapping, ... di array
var arr = [5, 6, 13, 0, 1, 18, 23];
var sum = arr.reduce((a, b) => a + b); // 66
var even = arr.filter(v => v % 2 == 0); // [6, 0, 18]
var double = arr.map(v => v * 2); // [10, 12, 26, 0, 2, 36, 46]
// Le catene di promise sono più concise
promise.then(a => {
// ...
}).then(b => {
// ...
});
24 . 10
77. Altri casi
// le funzioni a freccia senza parametri sono più semplici da visualizzare
setTimeout( () => {
console.log("I happen sooner");
setTimeout( () => {
console.log("I happen later");
}, 2000);
}, 1000);
24 . 13
78. Parameter Handling
Il parameter handling ha ricevuto
notevoli miglioramenti in ES6.
Default parameter values
Rest parameters
Named parameters via destructuring
Spread operator
25 . 1
79. Default Parameters
ES6 consente di definire valori di default
per i parametri
È inoltre possibile sfruttare altre variabili o altri parametri come valori di default
25 . 2
80. DEFAULT PARAMETERSDEFAULT PARAMETERS
function f(x, y=0) {
return [x, y];
}
function foo(x=3, y=x) {}
foo(); // x=3; y=3
foo(7); // x=7; y=7
foo(7, 2); // x=7; y=2
const x = 'outer';
function foo(a = x) {
const x = 'inner';
console.log(a); // outer
}
25 . 3
81. Rest Operator
Usando il prefisso ... prima di un ultimo parametro,
permette di rappresentare un indefinito numero di
argomenti come un array
non ci sono parametri a sufficienza, l'operatore rest sarà settato come un empty Array
25 . 4
83. REST OPERATORREST OPERATOR
Rest operator manda in pensione (o quasi) la variabile
speciale arguments
// ES5: arguments
function logAllArguments() {
for (var i=0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
// ES6: rest parameter
function logAllArguments(...args) {
for (const arg of args) {
console.log(arg);
}
}
25 . 6
84. Named Parameters
JavaScript non dispone di supporto nativo per i Named
Parameteres, ma offre una buona soluzione.
Utilizza una object literal per passare i parametri, che
sono quindi mappati.
Forniscono descrizioni per gli argomenti
nelle chiamate di funzione
Funzionano bene per i parametri opzionali
25 . 7
85. NAMED PARAMETERSNAMED PARAMETERS
// In ES6, puoi usare il destructuring
function selectEntries({ start=0, end=-1, step=1 } = {}) {
···
}
selectEntries({ step: 2 });
selectEntries({ end: 20, start: 3 });
selectEntries();
//In ECMAScript 5, selectEntries() si dovrebbe invece implementare come:
function selectEntries(options) {
options = options || {};
var start = options.start || 0;
var end = options.end || -1;
var step = options.step || 1;
···
}
25 . 8
86. REQUIRED PARAMETERSREQUIRED PARAMETERS
// ES5
function foo(mustBeProvided) {
if (arguments.length < 1) { throw new Error(); }
if (mustBeProvided === undefined) { throw new Error(); }
···
}
// ES6
// Chiamata se il parametro è assente
function mandatory() {
throw new Error('Missing parameter');
}
function foo(mustBeProvided = mandatory()) {
return mustBeProvided;
}
25 . 9
87. The spread operator (...)
Lo spread operator somiglia esattamente
al rest operator, ma:
Rest
operator
Raccoglie gli elementi restanti di un iterabile in un
array e viene utilizzato per rest parameters ed il
destructuring
Spread
operator
Trasforma gli elementi di un iterabile in argomenti di
una chiamata di funzione o in elementi di un array
25 . 10
89. SPREAD OPERATORSPREAD OPERATOR
new Date(...[1912, 11, 24])
const x = ['a', 'b'];
const y = ['c'];
const z = ['d', 'e'];
const arr = [...x, ...y, ...z]; // ['a', 'b', 'c', 'd', 'e']
const set = new Set([11, -1, 6]);
const arr = [...set]; // [11, -1, 6]
25 . 12
90. Classes
Le classi introdotte in ES6 sono un'evoluzione sintattica in
confronto alla versione prototype-based.
La sintassi non introduce un nuovo modello di ereditarietà ma una sintassi molto più semplice e
pulita per creare oggetti e gestire meglio l'ereditarietà stessa
26 . 1
91. CLASSCLASS
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return `(${this.x}, ${this.y})`;
}
}
var p = new Point(25, 8);
p.toString()
'(25, 8)'
26 . 2
92. CLASSCLASS
var o = {
a: 2,
m: function(b){
return this.a + 1;
}
};
console.log(o.m()); // 3
// Chiamando o.m in questo caso, 'this' si riferisce è o.a
var p = Object.create(o);
// p è un oggetto che eredita da o
p.a = 12; // crea una propria property 'a' su p
console.log(p.m()); // 13
26 . 3
93. Classes
Ereditarietà Singola
Metodo Constructor
Metodi Statici
Getter e Setter
Computed method names
Ereditarietà Mixin-style
Un'importante differenza tra la dichiarazione di una funzione e la dichiarazione di una classe è
che le dichiarazioni di funzione sono hoisted, quelle per le classi no.
Bisogna dichiarare la classe e poi usarla, altrimenti verrà sollevata un'eccezione
26 . 4
95. Ereditarietà
//ES6
class Rectangle extends Shape {
constructor (id, x, y, width, height) {
super(id, x, y)
this.width = width
this.height = height
}
}
class Circle extends Shape {
constructor (id, x, y, radius) {
super(id, x, y)
this.radius = radius
}
}
26 . 6
96. Ereditarietà
//ES5
var Rectangle = function (id, x, y, width, height) {
Shape.call(this, id, x, y);
this.width = width;
this.height = height;
};
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
var Circle = function (id, x, y, radius) {
Shape.call(this, id, x, y);
this.radius = radius;
};
Circle.prototype = Object.create(Shape.prototype);
Circle.prototype.constructor = Circle;
26 . 7
97. Super
class Cat {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noise.');
}
}
class Lion extends Cat {
speak() {
super.speak();
console.log(this.name + ' roars.');
}
}
26 . 8
98. Static Methods
//ES6
class Rectangle extends Shape {
…
static defaultRectangle () {
return new Rectangle("default", 0, 0, 100, 100)
}
}
class Circle extends Shape {
…
static defaultCircle () {
return new Circle("default", 0, 0, 100)
}
}
var defRectangle = Rectangle.defaultRectangle()
var defCircle = Circle.defaultCircle()
26 . 9
99. Static Methods
//ES5
var Rectangle = function (id, x, y, width, height) {
…
};
Rectangle.defaultRectangle = function () {
return new Rectangle("default", 0, 0, 100, 100);
};
var Circle = function (id, x, y, width, height) {
…
};
Circle.defaultCircle = function () {
return new Circle("default", 0, 0, 100);
};
var defRectangle = Rectangle.defaultRectangle();
var defCircle = Circle.defaultCircle();
26 . 10
100. Getter/Setter
//ES6
class Rectangle {
constructor (width, height) {
this._width = width
this._height = height
}
set width (width) { this._width = width }
get width () { return this._width }
set height (height) { this._height = height }
get height () { return this._height }
get area () { return this._width * this._height }
}
var r = new Rectangle(50, 20)
// r.area === 1000
26 . 11
101. Getter/Setter
//ES5
var Rectangle = function (width, height) {
this._width = width;
this._height = height;
};
Rectangle.prototype = {
set width (width) { this._width = width; },
get width () { return this._width; },
set height (height) { this._height = height; },
get height () { return this._height; },
get area () { return this._width * this._height; }
};
var r = new Rectangle(50, 20);
// r.area === 1000;
26 . 12
102. Class Expression
// unnamed
var Polygon = class {
constructor(height, width) {
this.height = height;
this.width = width;
}
};
// named
var Polygon = class Polygon {
constructor(height, width) {
this.height = height;
this.width = width;
}
};
26 . 13
103. Ereditarietà Mixin-style
class Person { ··· }
class Employee extends Person { ··· }
class Storage {
save(database) { ··· }
}
class Validation {
validate(schema) { ··· }
}
// Sarebbe bella una ES6 syntax:
class Employee extends Storage, Validation, Person { ··· }
26 . 14
105. Modules
ES6 ha aggiunto finalmente il supporto nativo ai moduli,
evitando il ricorso a soluzioni ad hoc e alla
implementazione del Module Pattern
Secondo le specifiche, un modulo JavaScript è memorizzato in un file:
esiste esattamente un modulo per file e un file contiene un solo modulo.
27 . 1
108. Export
//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
return x * x;
}
export function diag(x, y) {
return sqrt(square(x) + square(y));
}
// È anche possibile esportare più elementi
const sqrt = Math.sqrt;
function square(x) {
return x * x;
}
function diag(x, y) {
return sqrt(square(x) + square(y));
}
export {sqrt, square, diag};
27 . 4
109. Import
//------ main.js ------
import { square, diag } from 'lib';
console.log(square(11)); //121
console.log(diag(4,3)); //5
// È possibile usare degli alias
//------ main.js ------
import { square, diag as diagonal } from 'lib';
console.log(square(11)); // 121
console.log(diagonal(4, 3)); // 5
// Per importare l'intero modulo:
//------ main.js ------
import * as lib from 'lib';
console.log(lib.square(11)); // 121
console.log(lib.diag(4, 3)); // 5
27 . 5
110. Default Export
//------ myFunc.js ------
export default function () { ··· } // no semicolon!
//------ main1.js ------
import myFunc from 'myFunc';
myFunc();
//------ MyClass.js ------
export default class { ··· } // no semicolon!
//------ main2.js ------
import MyClass from 'MyClass';
const inst = new MyClass();
27 . 6
111. Alcune Note
L’importazione e l’esportazione di un modulo
sono processi statici
Non è possibile importare ed esportare un modulo a runtime in base alla valutazione di determinate condizioni
L’importazione di un modulo è soggetta ad hoisting
Gli elementi importati da un modulo sono in sola lettura
Questa funzionalità non ha ancora un supporto nativo crossbrowser, ma viene implementato in molti traspilers o
module bundlers come: Traceur Compiler, Babel, Rollup e Webpack.
27 . 7
112. Alcune Note
Ogni modulo viene eseguito una volta completamente caricato.
Nei moduli sono presenti dichiarazioni (dichiarazioni variabili,
dichiarazioni di funzione, ecc.).
Per impostazione predefinita, queste dichiarazioni rimangono locali nel modulo
È possibile contrassegnare alcune di esse come export, così che altri moduli possono importarli
27 . 8
113. Alcune Note
Un modulo può importare elementi da altri moduli, riferendosi
agli altri moduli con stringhe:
Relative paths ('../model/user')
Absolute paths ('/lib/js/helpers')
I Moduli sono singleton.
Questo approccio evita le variabili globali,
l'unica cosa globale sono i moduli stessi.
27 . 9
114. Array
Array.from Converte un array-like object in array
Array.of Un nuovo modo di creare array
Array.prototype.entries Ritorna un Array Iterator con
chiave/valore
Array.prototype.keys Ritorna un Array Iterator con chiave
Array.prototype.values Ritorna un Array Iterator con valore
28 . 1
115. Array
Array.prototype.find Ritorna il valore del primo elemento
che soddisfa i requisiti
Array.prototype.findIndex Ritorna l'indice del primo elemento
che soddisfa i requisiti
Array.prototype.fill Popola con un valore statico gli
elementi di un array da un indice di
partenza ad uno di fine
28 . 2
116. Maps/Sets (Collections)
Strutture dati molto comode per gestire insiemi,
così da evitare artifici per fare operazioni abbastanza
comuni.
Sets Un Set può contenere dati di qualsiasi tipo ma senza
duplicati.
Maps Il Map object è una semplice coppia chiave/valore.
Qualunque objects o primitive può essere usato sia come
chiave che valore.
29 . 1
117. Maps
var myMap = new Map();
var keyString = "a string",
keyObj = {},
keyFunc = function () {};
// Setting dei valori
myMap.set(keyString, "value associated with 'a string'");
myMap.set(keyObj, "value associated with keyObj");
myMap.set(keyFunc, "value associated with keyFunc");
myMap.size; // 3
29 . 2
118. Maps
// Getting dei valori
myMap.get(keyString); // "value associated with 'a string'"
myMap.get(keyObj); // "value associated with keyObj"
myMap.get(keyFunc); // "value associated with keyFunc"
myMap.get("a string"); // "value associated with 'a string'"
// perchè keyString === 'a string'
myMap.get({}); // undefined, perchè keyObj !== {}
myMap.get(function() {}) // undefined, perchè keyFunc !== function () {}
29 . 3
119. Sets
var mySet = new Set();
mySet.add(1); // Set { 1 }
mySet.add(5); // Set { 1, 5 }
mySet.add(5); // Set { 1, 5 }
mySet.add('some text'); // Set { 1, 5, 'some text' }
var o = {a: 1, b: 2};
mySet.add(o);
// o si riferisce ad un differente oggetto, quindi è consentito
mySet.add({a: 1, b: 2});
29 . 4
120. Sets
mySet.has(1); // true
mySet.has(3); // false, 3 non è stato aggiunto al Set
mySet.has(5); // true
mySet.has(Math.sqrt(25)); // true
mySet.has('Some Text'.toLowerCase()); // true
mySet.has(o); // true
mySet.size; // 5
mySet.delete(5); // Rimuove 5 dal set
mySet.has(5); // false, 5 è stato rimosso
mySet.size; // 4, abbiamo appena rimosso un valore
console.log(mySet);
// Set {1, "some text", Object {a: 1, b: 2}, Object {a: 1, b: 2}}
29 . 5
121. Symbol
Symbol è una nuova primitiva di ES6
Ogni qualvolta chiamamo la factory function, un nuovo symbol
univoco verrà creato.
let x = Symbol("mioSimbolo");
Symbols come chiave è una of non-public properties
(non sarà restituita da JSON.stringify o getOwnPropertyNames)
Un object sarà iterabile se esso avrà un metodo la quale chiave è
Symbol.iterator
30 . 1
122. Symbol
const symbol1 = Symbol();
> Symbol() === Symbol()
false
//Symbols può essere usato come chiave di una proprietà:
const MY_KEY = Symbol();
const FOO = Symbol();
const obj = {};
30 . 2
123. Symbol
obj[MY_KEY] = 123; //computed property keys
console.log(obj[MY_KEY]); // 123
const obj = {
data: [ 'hello', 'world' ],
[Symbol.iterator]() { ··· }
};
for (const x of obj) {
console.log(x);
}
// Output:
// hello
// world
30 . 3
124. Alcuni usi
Identificare un oggetto in maniera univoca assegnando un valore
alla sua proprietà id
Definizione di enumerazioni
(comunemente definiti con interi)
Definire una proprietà non visibile nell’elenco delle proprietà
dell’oggetto
Rendere iterabile una collezione di valori
(con l'uso di Symbol.iterator)
30 . 4
125. Iterators e Generators
L'elaborazione di ciascuno degli elementi di una
collezione è un'operazione molto comune.
JavaScript offre diversi modi di iterazione su una
raccolta, da semplici for loops a map() e filter().
Iterators e Generators portano il concetto di iterazione
direttamente nel core del linguaggio e forniscono un
meccanismo per personalizzare, ad esempio, il
comportamento di for...of.
31 . 1
126. Iterators
Un oggetto è definito Iterator se ha l'abilità di accedere gli
elementi di una collezione, uno alla volta e tenere traccia della
propria posizione nell'iterazione.
Un iteratore possiede il metodo next(), che ritorna il prossimo
elemento dell'iterazione.
Questo elemento ritornato, è un oggetto con due proprietà: done
e value.
String, Array, TypedArray, Map, Set, ... sono tutti iterabili predefiniti.
31 . 2
127. Generators
I generatori permettono di scrivere una funzione generatore
function* nome([param[, param[, ... param]]]) { }
che tiene traccia della propria posizione ed ha il metodo next().
I generatori ritornano un oggetto Generator.
La parola chiave yield viene usata per mettere in pausa e
riprendere l'esecuzione di una funzione generatore.
31 . 3
132. Generators
function* idMaker() {
var index = 0;
while(true)
yield index++;
}
var gen = idMaker();
console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
31 . 8
133. Generators
function* objectEntries(obj) {
const propKeys = Reflect.ownKeys(obj);
for (const propKey of propKeys) {
// `yield` ritorna un valore e mette in pausa il generator.
// Dopo l'esecuzione riprendere da dove era stata messa in pausa
yield [propKey, obj[propKey]];
}
}
const jane = { first: 'Jane', last: 'Doe' };
for (const [key,value] of objectEntries(jane)) {
console.log(`${key}: ${value}`);
}
// Output:
// first: Jane
// last: Doe
31 . 9
134. Objects Iterabili
var oggIterabile = {};
oggIterabile[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
for (let valore of oggIterabile) {
console.log(valore);
}
31 . 10
135. Async JS
Le operazioni asincrone sono sempre più comuni e
fortunatamente sempre più comode da gestire
È finito l'inferno delle callback...
benvenuti Promise ed Async/Await
Promise ed Async/Await consentono la gestione di
operazioni asincrone con semplicità ed enorme potenza
espressiva.
32 . 1
136. Promise
new Promise(function(resolve, reject) { ... });
Gli oggetti Promise sono usati per computazioni
in differita e asincrone.
Una Promise rappresenta un'operazione che non è ancora
completata, ma lo sarà in futuro.
Una Promise rappresenta un proxy per un valore non necessariamente noto quando la promise è stata creata.
32 . 2
137. Promise
Una Promise può presentarsi in uno dei seguenti stati:
pending (attesa) - stato iniziale, né soddisfatto né respinto.
fulfilled (soddisfatto) - significa che l'operazione si è conclusa con
sucesso.
rejected (respinto) - significa che l'operazione à fallita.
32 . 3
138. Promise
let myFirstPromise = new Promise((resolve, reject) => {
// Chiamiamo resolve(...) quando viene eseguito correttamente, e reject(...
// In questo esempio viene utilizzato setTimeout(...) per simulare un'opera
// Nella realtà probabilmente utilizzerai qualcosa del tipo XHR o HTML5 API
setTimeout(function(){
resolve("Success!"); // È andato tutto perfettamente!
}, 250);
});
myFirstPromise.then((successMessage) => {
// successMessage viene passato alla funzione resolve(...) .
// Non deve essere necessariamente una stringa, ma nel caso sia solo un mes
console.log("Yay! " + successMessage);
});
32 . 4
143. Promise
I metodi che fanno la differenza
Promise.all
Promise.race
Promise.resolve
Promise.reject
32 . 9
144. Async/Await
Una delle più attese novità introdotte da ECMAScript 2017 è stato
il supporto di async/await.
Si tratta di due parole chiave che abilitano la gestione di funzioni
asincrone eseguite tramite un approccio sincrono.
Consente la scrittura di codice asincrono pur mantenendo una struttura di codice tipico della programmazione
sincrona
Si basano sul meccanismo delle Promise e il loro risultato è compatibile con qualsiasi API che utilizza le Promise.
32 . 10
145. Async/Await
Async
La parola async prima di una funzione significa una
cosa semplice: una funzione restituisce sempre una
Promise.
32 . 11