Classes em ECMAScript 6

Com a nova versão do ECMAScript (6) finalizada em junho … é hora de fixar algo das novidades :D. Segue um apanhado que fiz (fontes abaixo) para entender melhor as peculiaridades das classes na nova encarnação do ECMAScript.

Classes no ES6 são apenas um açucar sintático sobre o padrão de OO baseado em protótipos do JavaScript de sempre e não um novo modelo de OO para a linguagem.
De qualquer maneira, essa nova forma é muito mais simples de usar e portanto encoraja o uso de OO. Vejamos a aparência de uma classe ES6:

1
2
3
4
5
6
7
8
9
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}

As classes no ES6, entretanto, não suportam ainda alguns features importantes. Vejamos rapidamente seus recursos e omissões.

  • Classes ES6 suportam:

    • construtor: método especial para criar e inicializar instâncias da classe.
    • métodos de instância
    • métodos estáticos: a keyword static define um método para a classe. Métodos estáticos são chamados diretamente pela classe (não pelas instâncias) e são normalmente usados para criar funções utilitárias relativas à instâncias da classe.
    • getters: métodos que permitem vincular uma “propriedade” da instância para uma função cujo retorno é oferecido sempre que a “propriedade” é acessada (ou seja, a propriedade retorna um valor dinamicamente computado).
    • setters: métodos que permitem vincular uma “propriedade” da instância para uma função que é invocada quando tentamos atribuir algo para a “propriedade” (podemos criar um par de setter/getter com o mesmo nome, simulando uma propriedade normal)
    • sub-classing: subclasses podem ser facilmente criadas usando a keyword extends.
    • super calls: a keyword super pode ser usada para invocar métodos da classe pai.
  • Classes ES6 não suportam:

    • inicializadores de propriedade: a sintaxe de definição de classe suporta apenas métodos (constructor, métodos estáticos e métodos da instância) e não propriedades, portanto não podemos utilizar foo = "bar"; ou foo : "bar"; dentro da definição da classe. Propriedades das instâncias, portanto, são normalmente definidas no constructor enquanto propriedades da classe são atribuídas após a definição da classe (var classe = class { }; classe.propDaClasse = "string").

A ausência de inicializadores de propriedade está sendo debatida atualmente na comunidade JS e as próximas versões do ES devem suprir essa carência.

Outras características de classes que considero importantes:

  • O escopo dos métodos da classe é dinâmico e não léxico. Significando que se passarmos o método como uma callback para outro escopo, o this obedecerá o comportamento normal de fn()s JavaScript e dependerá da forma como a função for invocada. Se quisermos que as funções que representam os métodos de instância sempre tenham a instância como this, podemos fazer:
1
2
3
4
5
6
7
8
9
class Counter {
constructor() {
super();
this.tick = this.tick.bind(this);
}
tick() {
console.log(this);
}
}
  • O resultado da definição de uma classe é apenas uma função:
1
2
> typeof Point
'function'
  • Apenas podemos instanciar uma classe usando new, não é possível fazer isso invocando a classe:
1
2
> Point()
TypeError: Classes can’t be function-called