ECMAScript 6 git.io/es6features

Introdução

ECMAScript 6, tambem conhecido como ECMAScript 2015, é a ultima versão do ECMAScript standard. ES6 é uma atualização significante para a linguagem, e a primeira atualização desde a ES5 se tornar padrão em 2009. A implementação dessas features nas principais engines JavaScript esta acontecendo agora.

Veja em ES6 standard a especificação completa.

ES6 adiciona as seguintes novas features:

ECMAScript 6 Features

Arrows

Arrows é um atalho para funções usando o simbolo =>. Elas são escritas de modo similar do C#, Java 8 e CoffeScript. Elas funcionam dentro de blocos statement assim como dentro do retorno de expressões. Diferentes das funções, arrows compartilham o mesmo this lexical como o codigo onde são declaradas.

// Dentro de expressões
var odds = evens.map(v => v + 1);
var nums = evens.map((v, i) => v + i);
var pairs = evens.map(v => ({even: v, odd: v + 1}));

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

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

Classes

Classes ES6 são relativamente simples quando comparatas com o padrão prototype-based OO. Tendo apenas uma forma conveniente de declaração torna as classes faceis de usar, e encoraja a interoperabilidade. Classes suportam herança prototype-based, super calls, instance, static methods e constructors.

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

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

Objetos Literais

Objetos Literais foram extendidos para suportar a configuração do prototype na construção, atalhos para foo: foo assignments, defining methods, super calls, e computing property names com expressões. Isso tambem faz com que objetos literais e classes ficam mais proximas, e deixa com que design object-based se beneficiem-se de alguma dessas vantagens.

var obj = {
    // __proto__
    __proto__: theProtoObj,
    // Shorthand for ‘handler: handler’
    handler,
    // Methods
    toString() {
     // Super calls
     return "d " + super.toString();
    },
    // Computed (dynamic) property names
    [ 'prop_' + (() => 42)() ]: 42
};

###Aprimoramento de Objetos Literais

Objetos Literais foram expandidos para suportar a configuração do prototype durante a sua construção, abreviações para foo: foo assignments, defining methods, fazer chamadas super, e o computing de property names com expressões. Juntos, eles deixam objetos literais e class declarations mais proximos, fazendo com que um design object-based tenha alguns beneficios.

    // __proto__
    __proto__: theProtoObj,
    // Shorthand for ‘handler: handler’
    handler,
    // Methods
    toString() {
     // Super calls
     return "d " + super.toString();
    },
    // Computed (dynamic) property names
    [ 'prop_' + (() => 42)() ]: 42
};```


### Template Strings
Template strings nos dá uma sintaxe melhor quando construimos strings. Isso é similar às features de string interpolation features em Perl ou em Python.  Opcionalmente, uma tag pode ser adicionada para fazer com que a construção de uma string seja constumizada, evitando ataques injection ou construindo estruturas de high level a partir do conteudo de strings.

```JavaScript
// Basica criação literal de strings
`In JavaScript '\n' is a line-feed.`

// Multiplicando strings
`In JavaScript this is
 not legal.`

// Interpolação de Strings 
var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`

// Construindo um HTTP request prefix que é usado para interpretar mudanças
GET`http://foo.org/bar?a=${a}&b=${b}
    Content-Type: application/json
    X-Credentials: ${credentials}
    { "foo": ${foo},
      "bar": ${bar}}`(myOnReadyStateChangeHandler);

Destructuring

Destructuring permite binding usando padrões de matching, com suporte para matching com array e objetos. Destructuring é fail-soft, similar ao padrão de object lookup foo["bar"], produzindo undefined quando valores não são encontrados.

// list matching
var [a, , b] = [1,2,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;

Default + Rest + Spread

Callee-evaluated default parameter values. Turn an array into consecutive arguments in a function call. Bind trailing parameters to an array. Rest replaces the need for arguments and addresses common cases more directly.

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

Block-scoped binding constructs. let é o novo var. const é single-assignment. Restrições Static são tem o uso previnido antes do assignment.

function f() {
  {
    let x;
    {
      // okay, block scoped name
      const x = "sneaky";
      // error, const
      x = "foo";
    }
    // error, already declared in block
    let x = "inner";
  }
}

Iterators + For..Of

Iterator objects permitem uma interação costumizada do tipo CLR IEnumerable ou Java Iterable. Normatizando for..in para uma iteration constumizada baseada em um for..of. Não precisa ser realizada em um array, permite padrões lazy design como 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);
}

Iteration is based on these duck-typed interfaces (using TypeScript type syntax for exposition only):

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

Generators

Generators simplificam a iterator-authoring usando function* e yield. Uma funcão declarada como function* retorna uma instancia Generator. Generators são um subtivo de iterators que incluem um adicional next e throw. Eles que os avlores voltem de volta para o generator, então yield é uma forma de expressão que retorna um valor (ou throws).

Nota: Tambem pode ser usado para permitir ‘await’-like programação asincrona, veja tambem a proposta await da 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);
}

The generator interface is (using TypeScript type syntax for exposition only):

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

Unicode

Melhorias no suporte à full Unicode, incluindo novas formas de Unicode literal em strings e tambem um novo modo u RegExp para lidar com code points, como tambem novas APIs para processar strings com um level de 21bit code. Essas adições faz com que o javascript possa ser escrito em qualquer idioma.

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

Modules

Language-level support for modules for component definition. Codifies patterns from popular JavaScript module loaders (AMD, CommonJS). Runtime behaviour defined by a host-defined default loader. Implicitly async model – no code executes until requested modules are available and processed.

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

Some additional features include export default and export *:

// lib/mathplusplus.js
export * from "lib/math";
export var e = 2.71828182846;
export default function(x) {
    return Math.log(x);
}
// app.js
import ln, {pi, e} from "lib/mathplusplus";
alert("2π = " + ln(e)*pi*2);

Module Loaders

Module loaders suportam:

  • Loading dinamico
  • Isolação de Estado
  • Isolação Global de namespace
  • Compilation hooks
  • Nested virtualization

O modulo loader padrão pode ser configurado, e novos loaders podem ser construidos para avaliar e carregar codigo em um contexto proximo ou isolado.

// 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

Map + Set + WeakMap + WeakSet

Estruturas de dados mais eficientes para algoritimos comuns. WeakMaps nos dá uma leak-free tabela object-key’d .

// 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

Proxies

Proxies permitem a criação de objetos com um range de comportamentos iguais aos seus host objects. Pode ser usado para intercepção, virtualização de objetos, logging/profiling, etc.

// 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 uma função objeto
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';

Essas são as traps disponiveis para todos as meta-operations do runtime-level:

var handler =
{
  get:...,
  set:...,
  has:...,
  deleteProperty:...,
  apply:...,
  construct:...,
  getOwnPropertyDescriptor:...,
  defineProperty:...,
  getPrototypeOf:...,
  setPrototypeOf:...,
  enumerate:...,
  ownKeys:...,
  preventExtensions:...,
  isExtensible:...
}

Symbols

Symbols permitem o controle do estado dos objetos. Symbols permite que propriedades possam ser usadas como string (como na ES5) ou symbol. Simbolos são um novo tipo primitivo. Parametro opcional description description usado no debugging - Mas não fazendo parte da identidade. Symbols são unicos (como gensym), mas não são privados desde que eles são expostos via features de felection, como Object.getOwnPropertySymbols.

var MyClass = (function() {

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

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

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

  return MyClass;
})();

var c = new MyClass("hello")
c["key"] === undefined

Subclassable Built-ins

Na ES6, built-ins do tipo Array, Date e DOM Elements podem ser usados para fazer subclasses.

A construção para uma função chamada Ctor agora usa two-phases (ambas virtualmente separadas):

  • Call Ctor[@@create] para alocar o objeto, instalando qualquer comportamento especial
  • Invocando construtor ou uma nova instancia no initialize

O symbol @@create esta disponivel via Symbol.create. Built-ins agora expõe seus @@create explicitamente.

// Pseudo-code of Array
class Array {
    constructor(...args) { /* ... */ }
    static [Symbol.create]() {
        // Install special [[DefineOwnProperty]]
        // to magically update 'length'
    }
}

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

// Two-phase 'new':
// 1) Call @@create to allocate object
// 2) Invoke constructor on new instance
var arr = new MyArray();
arr[1] = 12;
arr.length == 2

Math + Number + String + Array + Object APIs

Muitas novas bibliotecas de adição, incluindo bibliiotecas core Math, helpers para conversão de Arrays, helpers String, e Object.assign para copias.

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].find(x => x == 3) // 3
[1, 2, 3].findIndex(x => x == 2) // 1
[1, 2, 3, 4, 5].copyWithin(3, 0) // [1, 2, 3, 1, 2]
["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) })

Binarios e Literais Octais

Duas novas formas literais numeric foram adicionadas a binaria (b) e a octal (o).

0b111110111 === 503 // true
0o767 === 503 // true

Promises

Promises é a bibliioteca para programação assincrona. Promises é a primeira class representation de um valor que talvez esteja disponivel no futuro. Promisses são usadas em diversas bibliotecas já existentes dos 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)]);
})

Reflect API

Full reflection API nos tras as meta-operations do runtime-level nos objetos. Isso é efetivamente o inverso do Proxy API, e permite fazer calls correspondestes às mesmas operações como as proxy traps. Especialmente uteis quando implementando proxies.

// No sample yet

Tail Calls

Calls em tail-position são garantias para o não-crescimento de um stack sem controle. Fazendo com que algoritmos recursivos sejam seguros quando utilizando valores que podem ser infinitos (ou quase infinitos).

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

// Stack overflow na maior parte das implementações de hoje,
// Porem segura com inputs arbitrarios na ES6
factorial(100000)