Saltar al contenido principal

Aprender ES2015

Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

es6features

Este documento se basó originalmente en el excelente repositorio es6features de Luke Hoban. ¡Dale una estrella en GitHub!

REPL

Asegúrate de probar estas características en el REPL en línea.

Introducción

ECMAScript 2015 es un estándar ECMAScript ratificado en junio de 2015.

ES2015 es una actualización significativa del lenguaje, y la primera actualización importante desde que ES5 se estandarizó en 2009. La implementación de estas características en los principales motores JavaScript está en curso actualmente.

Consulta el estándar ES2015 para la especificación completa del lenguaje ECMAScript 2015.

Características de ECMAScript 2015

Funciones Flecha y this Léxico

Las funciones flecha son una sintaxis abreviada que usa =>. Son sintácticamente similares a características relacionadas en C#, Java 8 y CoffeeScript. Admiten tanto cuerpos de expresión como de declaración. A diferencia de las funciones normales, las flechas comparten el mismo this léxico que el código circundante. Si una flecha está dentro de otra función, comparte la variable "arguments" de su función padre.

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]

Clases

Las clases de ES2015 son azúcar sintáctico sobre el patrón OO basado en prototipos. Tener una única forma declarativa conveniente facilita el uso de patrones de clases y fomenta la interoperabilidad. Las clases admiten herencia basada en prototipos, llamadas super, métodos estáticos y de instancia, y constructores.

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();
}
}

Literales de Objeto Mejorados

Los literales de objeto se extienden para permitir establecer el prototipo durante la construcción, abreviar asignaciones foo: foo, definir métodos y hacer llamadas super. En conjunto, estos cambios acercan los literales de objeto y las declaraciones de clase, permitiendo que el diseño basado en objetos se beneficie de conveniencias similares.

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
};
precaución

La propiedad proto requiere soporte nativo y fue desaprobada en versiones anteriores de ECMAScript. La mayoría de motores actuales la admiten, pero some do not. Además, ten en cuenta que solo los web browsers están obligados a implementarla, ya que está en el Annex B. Está disponible en Node.

Plantillas de Cadena de Texto

Las plantillas de cadena proporcionan azúcar sintáctico para construir cadenas. Esto es similar a características de interpolación en Perl, Python y otros. Opcionalmente, se puede agregar una etiqueta para personalizar la construcción de cadenas, evitando ataques de inyección o construyendo estructuras de datos complejas a partir de contenido de cadenas.

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);

Desestructuración

La desestructuración permite enlazar mediante coincidencia de patrones, con soporte para arrays y objetos. Es tolerante a fallos, similar a la búsqueda estándar de objetos foo["bar"], produciendo valores undefined cuando no se encuentra.

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

Parámetros Predeterminados + Rest + Spread

Valores predeterminados evaluados en el contexto del llamante. Convierte un array en argumentos consecutivos en una llamada de función. Agrupa parámetros finales en un array. Rest reemplaza la necesidad de arguments y aborda casos comunes más directamente.

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

Constructos de enlace con ámbito de bloque. let es el nuevo var. const es de asignación única. Restricciones estáticas evitan su uso antes de la asignación.

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";
}
}

Iteradores + For..Of

Los objetos iteradores permiten iteración personalizada como CLR IEnumerable o Java Iterable. Generalizan for..in para iteración personalizada basada en iteradores mediante for..of. No requieren materializar un array, permitiendo patrones de diseño perezosos como 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);
}

La iteración se basa en estas interfaces de tipo pato (usando sintaxis de tipos de TypeScript solo para exposición):

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

Para usar Iteradores, debes incluir el polyfill de Babel.

Generadores

Los generadores simplifican la creación de iteradores usando function* y yield. Una función declarada como function* devuelve una instancia de Generator. Los generadores son subtipos de iteradores que incluyen next y throw adicionales. Permiten que valores fluyan de vuelta al generador, haciendo de yield una forma de expresión que devuelve un valor (o lanza excepción).

Nota: También pueden usarse para habilitar programación asíncrona similar a 'await', consulta también la propuesta ES7 await propuesta.

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);
}

La interfaz del generador es (usando sintaxis de tipos de TypeScript para exposición):

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

Para usar Generadores, debes incluir el polyfill de Babel.

Comprensiones

Eliminado en Babel 6.0

Unicode

Adiciones no disruptivas para soporte completo de Unicode, incluyendo nueva forma literal unicode en cadenas y nuevo modo u en RegExp para manejar puntos de código, así como nuevas APIs para procesar cadenas a nivel de puntos de código de 21 bits. Estas adiciones soportan construcción de aplicaciones globales en 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);
}

Módulos

Soporte a nivel de lenguaje para módulos para definición de componentes. Codifica patrones de cargadores de módulos JavaScript populares (AMD, CommonJS). Comportamiento en tiempo de ejecución definido por un cargador predeterminado definido por el host. Modelo implícitamente asíncrono: ningún código se ejecuta hasta que los módulos solicitados estén disponibles y procesados.

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));

Algunas características adicionales incluyen export default y 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));
Formatos de Módulos

Babel puede transpilar Módulos ES2015 a varios formatos diferentes incluyendo Common.js, AMD, System y UMD. Incluso puedes crear el tuyo. Para más detalles consulta la modules docs.

Cargadores de Módulos

No es parte de ES2015

Esto queda definido por la implementación en la especificación ECMAScript 2015. El estándar definitivo estará en la Loader specification de WHATWG, pero actualmente es trabajo en progreso. Lo siguiente es de un borrador anterior de ES2015.

Los cargadores de módulos soportan:

  • Carga dinámica

  • Aislamiento de estado

  • Aislamiento del espacio de nombres global

  • Hooks de compilación

  • Virtualización anidada

El cargador de módulos predeterminado puede configurarse, y se pueden construir nuevos cargadores para evaluar y cargar código en contextos aislados o restringidos.

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 adicional necesario

Como Babel usa módulos common.js por defecto, no incluye el polyfill para la API del cargador de módulos. Consíguelo here.

Usando el Cargador de Módulos

Para usar esto, necesitarás indicar a Babel que use el formateador de módulos system. También asegúrate de revisar System.js.

Map + Set + WeakMap + WeakSet

Estructuras de datos eficientes para algoritmos comunes. Los WeakMaps proporcionan tablas laterales con claves de objetos sin fugas de 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
Compatibilidad mediante polyfill

Para dar soporte a Maps, Sets, WeakMaps y WeakSets en todos los entornos, debes incluir el polyfill de Babel.

Proxies

Los Proxies permiten crear objetos con todo el rango de comportamientos disponibles para objetos host. Se pueden usar para intercepción, virtualización de objetos, registro/profilado, etc.

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";

Existen trampas disponibles para todas las meta-operaciones a nivel de tiempo de ejecución:

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 :...
}
Característica no soportada

Debido a las limitaciones de ES5, los Proxies no se pueden transpilar ni aplicar mediante polyfill. Consulta el soporte en various JavaScript engines.

Symbols

Los Symbols permiten control de acceso al estado de objetos. Permiten que las propiedades se indexen mediante string (como en ES5) o symbol. Son un nuevo tipo primitivo. El parámetro opcional name se usa en depuración pero no forma parte de la identidad. Los Symbols son únicos (como gensym), pero no privados ya que se exponen mediante características de reflexión como 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
Soporte limitado mediante polyfill

El soporte limitado requiere el polyfill de Babel. Debido a limitaciones del lenguaje, algunas características no se pueden transpilar ni aplicar mediante polyfill. Consulta la caveats section de core.js para más detalles.

Clases integradas que pueden extenderse

En ES2015, las clases integradas como Array, Date y los Element del DOM pueden extenderse mediante herencia.

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

var arr = new MyArray();
arr[1] = 12;
arr.length == 2
Soporte parcial

La capacidad de extender clases integradas debe evaluarse caso por caso: clases como HTMLElement can extenderse, mientras que Date, Array y Error cannot debido a limitaciones de motores ES5.

APIs de Math, Number, String y Object

Numerosas adiciones a bibliotecas, incluyendo núcleos matemáticos, ayudantes para conversión de arrays, y Object.assign para 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) })
Soporte limitado mediante polyfill

La mayoría de estas APIs están soportadas por el polyfill de Babel. Ciertas características se omiten por varias razones (ej. String.prototype.normalize requiere mucho código adicional). Encuentra más polyfills here.

Literales binarios y octales

Se añaden dos nuevas formas de literales numéricos para binario (b) y octal (o).

JavaScript
0b111110111 === 503 // true
0o767 === 503 // true
Solo soporta forma literal

Babel solo puede transformar 0o767 y no Number("0o767").

Promesas

Las Promesas son una biblioteca para programación asíncrona. Representan valores que podrían estar disponibles en el futuro. Se usan en muchas bibliotecas JavaScript existentes.

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)]);
})
Compatibilidad mediante polyfill

Para dar soporte a Promesas, debes incluir el polyfill de Babel.

API Reflect

API de reflexión completa que expone las metaoperaciones a nivel de tiempo de ejecución sobre objetos. Esta funcionalidad es esencialmente la inversa de la API Proxy, y permite realizar llamadas correspondientes a las mismas metaoperaciones que las trampas de los proxies. Es especialmente útil para implementar proxies.

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
Soporte mediante polyfill

Para usar la API Reflect debes incluir el polyfill de Babel.

Llamadas de Cola

Las llamadas en posición de cola garantizan que la pila no crezca indefinidamente. Hace que los algoritmos recursivos sean seguros frente a entradas de tamaño ilimitado.

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)
Eliminado temporalmente en Babel 6

Solo se admitía recursión de cola explícita autorreferenciada debido a la complejidad y el impacto en el rendimiento de soportar llamadas de cola globalmente. Se eliminó por otros errores y será reimplementado.