Impara ES2015
Questa pagina è stata tradotta da PageTurner AI (beta). Non ufficialmente approvata dal progetto. Hai trovato un errore? Segnala problema →
Questo documento è originariamente tratto dall'eccellente repository es6features di Luke Hoban. Dagli una stella su GitHub!
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.
// 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.
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à.
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
};
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.
// 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.
// 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.
function f(x, y=12) {
// y is 12 if not passed (or passed as undefined)
return x + y;
}
f(3) == 15
function f(x, ...y) {
// y is an Array
return x * y.length;
}
f(3, "hello", true) == 6
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.
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.
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
}
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.
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);
}
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.
// 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.
// lib/math.js
export function sum(x, y) {
return x + y;
}
export var pi = 3.141593;
// app.js
import * as math from "lib/math";
console.log("2π = " + math.sum(math.pi, math.pi));
// otherApp.js
import {sum, pi} from "lib/math";
console.log("2π = " + sum(pi, pi));
Alcune funzionalità aggiuntive includono export default e export *:
// lib/mathplusplus.js
export * from "lib/math";
export var e = 2.71828182846;
export default function(x) {
return Math.exp(x);
}
// app.js
import exp, {pi, e} from "lib/mathplusplus";
console.log("e^π = " + exp(pi));
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
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.
// 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
Poiché Babel utilizza predefinitamente i moduli common.js, non include il polyfill per l'API del loader di moduli. Scaricalo here.
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.
// 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
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.
// 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!";
// 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:
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 :...
}
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.
(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
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.
// User code of Array subclass
class MyArray extends Array {
constructor(...args) { super(...args); }
}
var arr = new MyArray();
arr[1] = 12;
arr.length == 2
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.
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) })
Letterali binari e ottali
Sono state aggiunte due nuove forme di letterali numerici per i binari (b) e gli ottali (o).
0b111110111 === 503 // true
0o767 === 503 // true
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.
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)]);
})
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.
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
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.
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)
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.