Vai al contenuto principale

Impara ES2015

Traduzione Beta Non Ufficiale

Questa pagina è stata tradotta da PageTurner AI (beta). Non ufficialmente approvata dal progetto. Hai trovato un errore? Segnala problema →

es6features

Questo documento è originariamente tratto dall'eccellente repository es6features di Luke Hoban. Dagli una stella su GitHub!

REPL

Assicurati di provare queste funzionalità nel REPL online.

Introduzione

ECMAScript 2015 è uno standard ECMAScript ratificato nel giugno 2015.

ES2015 rappresenta un aggiornamento significativo del linguaggio, il primo aggiornamento importante dalla standardizzazione di ES5 nel 2009. L'implementazione di queste funzionalità nei principali motori JavaScript è attualmente in corso.

Consulta lo standard ES2015 per la specifica completa del linguaggio ECMAScript 2015.

Funzionalità di ECMAScript 2015

Funzioni Freccia e This Lessicale

Le funzioni freccia sono una sintassi abbreviata che utilizza =>. Sono sintatticamente simili alle funzionalità correlate in C#, Java 8 e CoffeeScript. Supportano sia corpi di espressione che di istruzione. A differenza delle funzioni tradizionali, le frecce condividono lo stesso this lessicale del codice circostante. Se una freccia è all'interno di un'altra funzione, condivide la variabile "arguments" della funzione genitore.

JavaScript
// Expression bodies
var odds = evens.map(v => v + 1);
var nums = evens.map((v, i) => v + i);

// Statement bodies
nums.forEach(v => {
if (v % 5 === 0)
fives.push(v);
});

// Lexical this
var bob = {
_name: "Bob",
_friends: [],
printFriends() {
this._friends.forEach(f =>
console.log(this._name + " knows " + f));
}
};

// Lexical arguments
function square() {
let example = () => {
let numbers = [];
for (let number of arguments) {
numbers.push(number * number);
}

return numbers;
};

return example();
}

square(2, 4, 7.5, 8, 11.5, 21); // returns: [4, 16, 56.25, 64, 132.25, 441]

Classi

Le classi ES2015 sono zucchero sintattico sul pattern OO basato su prototipi. Avere una singola forma dichiarativa conveniente rende più semplice l'uso dei pattern di classe e favorisce l'interoperabilità. Le classi supportano ereditarietà basata su prototipi, chiamate super, metodi di istanza e statici, e costruttori.

JavaScript
class SkinnedMesh extends THREE.Mesh {
constructor(geometry, materials) {
super(geometry, materials);

this.idMatrix = SkinnedMesh.defaultMatrix();
this.bones = [];
this.boneMatrices = [];
//...
}
update(camera) {
//...
super.update();
}
static defaultMatrix() {
return new THREE.Matrix4();
}
}

Oggetti Letterali Avanzati

Gli oggetti letterali sono estesi per supportare l'impostazione del prototipo durante la costruzione, la sintassi abbreviata per assegnazioni foo: foo, la definizione di metodi e le chiamate super. Insieme, questi aspetti avvicinano anche gli oggetti letterali e le dichiarazioni di classe, permettendo alla progettazione basata su oggetti di beneficiare delle stesse comodità.

JavaScript
var obj = {
// Sets the prototype. "__proto__" or '__proto__' would also work.
__proto__: theProtoObj,
// Computed property name does not set prototype or trigger early error for
// duplicate __proto__ properties.
['__proto__']: somethingElse,
// Shorthand for ‘handler: handler’
handler,
// Methods
toString() {
// Super calls
return "d " + super.toString();
},
// Computed (dynamic) property names
[ "prop_" + (() => 42)() ]: 42
};
attenzione

La proprietà proto richiede supporto nativo ed è stata deprecata nelle versioni precedenti di ECMAScript. La maggior parte dei motori ora supporta la proprietà, ma some do not. Inoltre, nota che solo i web browsers sono tenuti a implementarla, poiché si trova nell'Annex B. È disponibile in Node.

Template String

I template string forniscono zucchero sintattico per costruire stringhe. Sono simili alle funzionalità di interpolazione stringa in Perl, Python e altri linguaggi. Opzionalmente, è possibile aggiungere un tag per personalizzare la costruzione della stringa, prevenendo attacchi di injection o costruendo strutture dati complesse dai contenuti delle stringhe.

JavaScript
// Basic literal string creation
`This is a pretty little template string.`

// Multiline strings
`In ES5 this is
not legal.`

// Interpolate variable bindings
var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`

// Unescaped template strings
String.raw`In ES5 "\n" is a line-feed.`

// Construct an HTTP request prefix is used to interpret the replacements and construction
GET`http://foo.org/bar?a=${a}&b=${b}
Content-Type: application/json
X-Credentials: ${credentials}
{ "foo": ${foo},
"bar": ${bar}}`(myOnReadyStateChangeHandler);

Destrutturazione

La destrutturazione consente l'associazione tramite pattern matching, con supporto per array e oggetti. È fail-soft, simile alla normale ricerca in oggetti foo["bar"], producendo valori undefined quando non trovata.

JavaScript
// list matching
var [a, ,b] = [1,2,3];
a === 1;
b === 3;

// object matching
var { op: a, lhs: { op: b }, rhs: c }
= getASTNode()

// object matching shorthand
// binds `op`, `lhs` and `rhs` in scope
var {op, lhs, rhs} = getASTNode()

// Can be used in parameter position
function g({name: x}) {
console.log(x);
}
g({name: 5})

// Fail-soft destructuring
var [a] = [];
a === undefined;

// Fail-soft destructuring with defaults
var [a = 1] = [];
a === 1;

// Destructuring + defaults arguments
function r({x, y, w = 10, h = 10}) {
return x + y + w + h;
}
r({x:1, y:2}) === 23

Default + Rest + Spread

Valori predefiniti per parametri valutati dal chiamante. Trasforma un array in argomenti consecutivi in una chiamata di funzione. Associa i parametri finali a un array. Rest sostituisce la necessità di arguments e affronta casi comuni più direttamente.

JavaScript
function f(x, y=12) {
// y is 12 if not passed (or passed as undefined)
return x + y;
}
f(3) == 15
JavaScript
function f(x, ...y) {
// y is an Array
return x * y.length;
}
f(3, "hello", true) == 6
JavaScript
function f(x, y, z) {
return x + y + z;
}
// Pass each elem of array as argument
f(...[1,2,3]) == 6

Let + Const

Costrutti di binding con ambito a blocco. let è il nuovo var. const è a singola assegnazione. Restrizioni statiche prevengono l'uso prima dell'assegnazione.

JavaScript
function f() {
{
let x;
{
// this is ok since it's a block scoped name
const x = "sneaky";
// error, was just defined with `const` above
x = "foo";
}
// this is ok since it was declared with `let`
x = "bar";
// error, already declared above in this block
let x = "inner";
}
}

Iteratori + For..Of

Gli oggetti iteratore consentono iterazioni personalizzate simili a IEnumerable di CLR o Iterable di Java. Generalizzano for..in per iterazioni basate su iteratori personalizzati con for..of. Non richiedono la materializzazione di un array, abilitando pattern di progettazione lazy come LINQ.

JavaScript
let fibonacci = {
[Symbol.iterator]() {
let pre = 0, cur = 1;
return {
next() {
[pre, cur] = [cur, pre + cur];
return { done: false, value: cur }
}
}
}
}

for (var n of fibonacci) {
// truncate the sequence at 1000
if (n > 1000)
break;
console.log(n);
}

L'iterazione si basa su queste interfacce duck-typed (utilizzando la sintassi dei tipi di TypeScript solo a scopo illustrativo):

interface IteratorResult {
done: boolean;
value: any;
}
interface Iterator {
next(): IteratorResult;
}
interface Iterable {
[Symbol.iterator](): Iterator
}
Supporto tramite polyfill

Per utilizzare gli Iteratori è necessario includere il polyfill di Babel.

Generatori

I generatori semplificano la creazione di iteratori utilizzando function* e yield. Una funzione dichiarata come function* restituisce un'istanza di Generator. I generatori sono sottotipi di iteratori che includono metodi aggiuntivi next e throw. Questi consentono ai valori di fluire nuovamente nel generatore, quindi yield è una forma di espressione che restituisce un valore (o solleva un'eccezione).

Nota: Possono anche essere utilizzati per abilitare una programmazione asincrona simile ad 'await', vedi anche la proposta per await in ES7.

JavaScript
var fibonacci = {
[Symbol.iterator]: function*() {
var pre = 0, cur = 1;
for (;;) {
var temp = pre;
pre = cur;
cur += temp;
yield cur;
}
}
}

for (var n of fibonacci) {
// truncate the sequence at 1000
if (n > 1000)
break;
console.log(n);
}

L'interfaccia del generatore è (utilizzando la sintassi dei tipi di TypeScript solo a scopo illustrativo):

interface Generator extends Iterator {
next(value?: any): IteratorResult;
throw(exception: any);
}
Supporto tramite polyfill

Per utilizzare i Generatori è necessario includere il polyfill di Babel.

Comprensioni

Rimosso in Babel 6.0

Unicode

Aggiunte non disruptive per supportare Unicode completo, inclusa la nuova forma letterale unicode nelle stringhe e la nuova modalità u di RegExp per gestire i code point, oltre a nuove API per elaborare stringhe a livello di code point a 21 bit. Queste aggiunte supportano la creazione di applicazioni globali in JavaScript.

JavaScript
// same as ES5.1
"𠮷".length == 2

// new RegExp behaviour, opt-in ‘u’
"𠮷".match(/./u)[0].length == 2

// new form
"\u{20BB7}" == "𠮷"
"𠮷" == "\uD842\uDFB7"

// new String ops
"𠮷".codePointAt(0) == 0x20BB7

// for-of iterates code points
for(var c of "𠮷") {
console.log(c);
}

Moduli

Supporto a livello di linguaggio per moduli nella definizione dei componenti. Codifica pattern da popolari JavaScript module loader (AMD, CommonJS). Comportamento a runtime definito da un loader predefinito specificato dall'host. Modello implicitamente asincrono – nessun codice viene eseguito finché i moduli richiesti non sono disponibili ed elaborati.

JavaScript
// lib/math.js
export function sum(x, y) {
return x + y;
}
export var pi = 3.141593;
JavaScript
// app.js
import * as math from "lib/math";
console.log("2π = " + math.sum(math.pi, math.pi));
JavaScript
// otherApp.js
import {sum, pi} from "lib/math";
console.log("2π = " + sum(pi, pi));

Alcune funzionalità aggiuntive includono export default e export *:

JavaScript
// lib/mathplusplus.js
export * from "lib/math";
export var e = 2.71828182846;
export default function(x) {
return Math.exp(x);
}
JavaScript
// app.js
import exp, {pi, e} from "lib/mathplusplus";
console.log("e^π = " + exp(pi));
Formattatori di moduli

Babel può transpilare i moduli ES2015 in diversi formati tra cui Common.js, AMD, System e UMD. Puoi persino crearne uno tuo. Per maggiori dettagli consulta la modules docs.

Loader di moduli

Non fa parte di ES2015

Questo aspetto è lasciato come definizione implementativa nella specifica ECMAScript 2015. Lo standard definitivo sarà nella Loader specification di WHATWG, attualmente in lavorazione. Quanto segue proviene da una bozza precedente di ES2015.

I loader di moduli supportano:

  • Caricamento dinamico

  • Isolamento dello stato

  • Isolamento del namespace globale

  • Hook di compilazione

  • Virtualizzazione annidata

Il loader di moduli predefinito può essere configurato e nuovi loader possono essere costruiti per valutare e caricare codice in contesti isolati o vincolati.

JavaScript
// Dynamic loading – ‘System’ is default loader
System.import("lib/math").then(function(m) {
alert("2π = " + m.sum(m.pi, m.pi));
});

// Create execution sandboxes – new Loaders
var loader = new Loader({
global: fixup(window) // replace ‘console.log’
});
loader.eval("console.log(\"hello world!\");");

// Directly manipulate module cache
System.get("jquery");
System.set("jquery", Module({$: $})); // WARNING: not yet finalized
Polyfill aggiuntivo necessario

Poiché Babel utilizza predefinitamente i moduli common.js, non include il polyfill per l'API del loader di moduli. Scaricalo here.

Utilizzo del loader di moduli

Per utilizzarlo, devi dire a Babel di usare il formattatore di moduli system. Consulta anche System.js.

Map + Set + WeakMap + WeakSet

Strutture dati efficienti per algoritmi comuni. WeakMap fornisce tabelle laterali con chiavi oggetto senza perdite di memoria.

JavaScript
// Sets
var s = new Set();
s.add("hello").add("goodbye").add("hello");
s.size === 2;
s.has("hello") === true;

// Maps
var m = new Map();
m.set("hello", 42);
m.set(s, 34);
m.get(s) == 34;

// Weak Maps
var wm = new WeakMap();
wm.set(s, { extra: 42 });
wm.size === undefined

// Weak Sets
var ws = new WeakSet();
ws.add({ data: 42 });
// Because the added object has no other references, it will not be held in the set
Supporto tramite polyfill

Per supportare Map, Set, WeakMap e WeakSet in tutti gli ambienti, è necessario includere il polyfill di Babel.

Proxy

I Proxy consentono la creazione di oggetti con l'intera gamma di comportamenti disponibili agli oggetti host. Possono essere utilizzati per intercezione, virtualizzazione di oggetti, logging/profiling, ecc.

JavaScript
// Proxying a normal object
var target = {};
var handler = {
get: function (receiver, name) {
return `Hello, ${name}!`;
}
};

var p = new Proxy(target, handler);
p.world === "Hello, world!";
JavaScript
// Proxying a function object
var target = function () { return "I am the target"; };
var handler = {
apply: function (receiver, ...args) {
return "I am the proxy";
}
};

var p = new Proxy(target, handler);
p() === "I am the proxy";

Sono disponibili trappole per tutte le operazioni meta a livello di runtime:

JavaScript
var handler =
{
// target.prop
get: ...,
// target.prop = value
set: ...,
// 'prop' in target
has: ...,
// delete target.prop
deleteProperty: ...,
// target(...args)
apply: ...,
// new target(...args)
construct: ...,
// Object.getOwnPropertyDescriptor(target, 'prop')
getOwnPropertyDescriptor: ...,
// Object.defineProperty(target, 'prop', descriptor)
defineProperty: ...,
// Object.getPrototypeOf(target), Reflect.getPrototypeOf(target),
// target.__proto__, object.isPrototypeOf(target), object instanceof target
getPrototypeOf: ...,
// Object.setPrototypeOf(target), Reflect.setPrototypeOf(target)
setPrototypeOf: ...,
// Object.keys(target)
ownKeys: ...,
// Object.preventExtensions(target)
preventExtensions: ...,
// Object.isExtensible(target)
isExtensible :...
}
Funzionalità non supportata

A causa delle limitazioni di ES5, i Proxy non possono essere transpilati né polifillati. Consulta il supporto nei various JavaScript engines.

Simboli

I Simboli abilitano il controllo di accesso allo stato degli oggetti. Consentono di associare proprietà a chiavi di tipo string (come in ES5) o symbol. Sono un nuovo tipo primitivo. Il parametro name opzionale è utile per il debug ma non fa parte dell'identità. I Simboli sono univoci (simili a gensym), ma non privati poiché esposti tramite funzionalità di reflection come Object.getOwnPropertySymbols.

JavaScript
(function() {

// module scoped symbol
var key = Symbol("key");

function MyClass(privateData) {
this[key] = privateData;
}

MyClass.prototype = {
doStuff: function() {
... this[key] ...
}
};

// Limited support from Babel, full support requires native implementation.
typeof key === "symbol"
})();

var c = new MyClass("hello")
c["key"] === undefined
Supporto limitato tramite polyfill

Il supporto limitato richiede il polyfill di Babel. A causa di limitazioni del linguaggio, alcune funzionalità non possono essere transpilate né polifillate. Consulta la caveats section per maggiori dettagli.

Oggetti integrati estendibili

In ES2015, oggetti integrati come Array, Date ed Element del DOM possono essere estesi.

JavaScript
// User code of Array subclass
class MyArray extends Array {
constructor(...args) { super(...args); }
}

var arr = new MyArray();
arr[1] = 12;
arr.length == 2
Supporto parziale

L'estendibilità degli oggetti integrati deve essere valutata caso per caso: classi come HTMLElement can essere estese, mentre molte altre come Date, Array ed Error cannot esserlo a causa di limitazioni dei motori ES5.

API per Math, Number, String e Object

Numerose aggiunte alle librerie, tra cui funzioni matematiche di base, helper per la conversione di array e Object.assign per la copia.

JavaScript
Number.EPSILON
Number.isInteger(Infinity) // false
Number.isNaN("NaN") // false

Math.acosh(3) // 1.762747174039086
Math.hypot(3, 4) // 5
Math.imul(Math.pow(2, 32) - 1, Math.pow(2, 32) - 2) // 2

"abcde".includes("cd") // true
"abc".repeat(3) // "abcabcabc"

Array.from(document.querySelectorAll("*")) // Returns a real Array
Array.of(1, 2, 3) // Similar to new Array(...), but without special one-arg behavior
[0, 0, 0].fill(7, 1) // [0,7,7]
[1,2,3].findIndex(x => x == 2) // 1
["a", "b", "c"].entries() // iterator [0, "a"], [1,"b"], [2,"c"]
["a", "b", "c"].keys() // iterator 0, 1, 2
["a", "b", "c"].values() // iterator "a", "b", "c"

Object.assign(Point, { origin: new Point(0,0) })
Supporto limitato dal polyfill

La maggior parte di queste API è supportata dal polyfill di Babel. Tuttavia, alcune funzionalità sono omesse per vari motivi (ad esempio String.prototype.normalize richiede molto codice aggiuntivo). Altri polyfill sono disponibili here.

Letterali binari e ottali

Sono state aggiunte due nuove forme di letterali numerici per i binari (b) e gli ottali (o).

JavaScript
0b111110111 === 503 // true
0o767 === 503 // true
Supporta solo la forma letterale

Babel è in grado di trasformare solo 0o767 e non Number("0o767").

Promise

Le Promise sono una libreria per la programmazione asincrona. Rappresentano di prima classe un valore che potrebbe essere disponibile in futuro. Sono utilizzate in molte librerie JavaScript esistenti.

JavaScript
function timeout(duration = 0) {
return new Promise((resolve, reject) => {
setTimeout(resolve, duration);
})
}

var p = timeout(1000).then(() => {
return timeout(2000);
}).then(() => {
throw new Error("hmm");
}).catch(err => {
return Promise.all([timeout(100), timeout(200)]);
})
Supporto tramite polyfill

Per supportare le Promise, è necessario includere il Babel polyfill.

API Reflect

Una API Reflection completa che espone le operazioni meta a livello di runtime sugli oggetti. È di fatto l'inverso dell'API Proxy e consente di effettuare chiamate corrispondenti alle stesse operazioni meta delle trappole (traps) dei proxy. Particolarmente utile per implementare i proxy.

JavaScript
var O = {a: 1};
Object.defineProperty(O, 'b', {value: 2});
O[Symbol('c')] = 3;

Reflect.ownKeys(O); // ['a', 'b', Symbol(c)]

function C(a, b){
this.c = a + b;
}
var instance = Reflect.construct(C, [20, 22]);
instance.c; // 42
Supporto tramite polyfill

Per usare l'API Reflect devi includere il polyfill di Babel.

Chiamate in Coda

Le chiamate in posizione di coda sono garantite per non far crescere lo stack in modo illimitato. Rende sicuri gli algoritmi ricorsivi di fronte a input illimitati.

JavaScript
function factorial(n, acc = 1) {
"use strict";
if (n <= 1) return acc;
return factorial(n - 1, n * acc);
}

// Stack overflow in most implementations today,
// but safe on arbitrary inputs in ES2015
factorial(100000)
Rimosso temporaneamente in Babel 6

Era supportata solo la ricorsione in coda esplicita con riferimento a sé stessa a causa della complessità e dell'impatto sulle prestazioni del supporto globale delle chiamate in coda. Rimosso a causa di altri bug e verrà reimplementato.