Entenda a nova especificação de classes do JavaScript Harmony ES6

Entenda a nova especificação de classes do JavaScript Harmony ES6
leonardo.wolter
leonardo.wolter

Compartilhe

Há tempos a criação de classes e objetos em JavaScript tem sido complexa e difícil de entender, isso por conta de não existir uma linha clara dividindo classes de funções e objetos e, com isso, existirem diversas maneiras de se criar estes bem como diversas formas de utilizar praticas de P.O.O. como a herança.

Por estes motivos, o ECMAScript6 (também conhecido como Harmony, ES.next ou ES6) prevê uma nova especificação chamada maximally_minimal_classes, que tem como objetivo uniformizar e simplificar a definição de classes do modo mais minimalista possível.

Atualmente, o modo mais usado para se definir algo parecido com uma classe em JavaScript é utilizando uma função construtora e adicionando funções ao seu protótipo. Confira abaixo como ficaria a representação de uma Pessoa deste modo:

 var Pessoa = function(nome, email) { this.nome = nome; // verifica se o e-mail foi preenchido if (email) { this.email = email; } }; Pessoa.prototype.fala = function(){ console.log("Olá, meu nome é "+this.nome+" e meu email é "+this.email); }; 

Note que a sintaxe não é exatamente intuitiva, deste modo você precisaria saber o que é um prototype e que, em JavaScript, uma classe é uma função no final das contas, o que tende a confundir bastante a cabeça de desenvolvedores acostumados com P.O.O.

Agora vamos ver como ficaria uma Pessoa utilizando a nova especificação:

 class Pessoa{ constructor(nome, email){ this.nome = nome; // verifica se o e-mail foi preenchido if (email) { this.email = email; } }

fala(){ console.log("Olá, meu nome é "+this.nome+" e meu email é "+this.email); } } var leo = new Pessoa("Leonardo", "[email protected]"); leo.fala(); // Olá, meu nome é Leonardo e meu email é [email protected] 

Caso você já programe em uma linguagem orientada a objetos como o Java, essa sintaxe provavelmente será muito mais intuitiva que a anterior.

Um detalhe interessante dessa abordagem é que, apesar de a função fala ser declarada dentro da classe Pessoa, ela será adicionada no prototype da Pessoa, o que pode ser visivelmente mais performático do que adicioná-la diretamente na função.

Apesar de ser muito parecido com Java, essa especificação não adicionará modificadores de acesso, o que significa que todos os atributos ou métodos adicionados à classe serão públicos! Como a própria especificação diz: "private is simply achieved via private name objects".

Além da definição padrão de classes citada acima, também estará disponível uma maneira de criar pseudo-propriedades simplesmente adicionando a palavra get ou set antes do nome da função, assim como você pode fazer em objetos literais. Exemplo:

 class Pessoa { constructor(nome, email) { this.nome = nome; this.comidas = \[\]; // verifica se o e-mail foi preenchido if (email) { this.email = email; } }

fala() { console.log("Olá, meu nome é "+this.nome+" e meu email é "+this.email); }

get primeiroNome() { return this.nome.split(" ")\[0\]; }

set gostaDe(comida) { this.comidas.push(comida); } }

var leo = new Pessoa("Leonardo Wolter", "[email protected]"); leo.gostaDe = "bolo"; console.log(leo.comidas); // ```"bolo"
 console.log(leo.primeiroNome); // Leonardo 

Agora conseguimos criar uma classe com uma sintaxe melhor, legal, mas e as heranças, como ficam?

Atualmente, o modo mais utilizado de se implementar herança é utilizando o Prototype-Chainning. Imagine que temos uma classe PessoaFisica que herda Pessoa. O código seria parecido com este: ```js

var PessoaFisica = function(nome, email, cpf){ Pessoa.call(this, nome, email); this.cpf = cpf; }; PessoaFisica.prototype = new Pessoa(); PessoaFisica.prototype.constructor = PessoaFisica; PessoaFisica.prototype.dizCpf = function(){ console.log(this.cpf); };


Resumindo você precisaria criar uma função construtora com o conteudo adequado, setar o prototype de `PessoaFisica` com uma instancia de `Pessoa`, consertar a propriedade construtor e, por ultimo mas nao menos importante, adicionar as funções específicas sua `PessoaFisica`.

Confira agora como implementaríamos a mesma herança utilizando a nova especificação:

```js

class PessoaFisica extends Pessoa{

constructor(nome, email, cpf){ super(nome, email); this.cpf = cpf; } dizCpf(){ console.log(this.cpf); } }

var leo = new PessoaFisica("Leonardo", "[email protected]", "meucpf" ); leo.gostaDe = "bolo"; console.log(leo.comidas); // ```"bolo"
 console.log(leo.idade); // 63 leo.dizCpf(); // "meucpf" leo.fala(); // Olá, meu nome é Leonardo e meu email é [email protected]

Temos como resultado um código mais expressivo e enxuto, apenas utilizamos a palavra-chave extends para dizer que a PessoaFisica herda Pessoa e substituimos a estratégia de Constructor Stealing pelo código super(nome, email)

Legal, e quando eu vou poder usar isso? Atualmente, apenas o traceur-compiler possui suporte a essa nova sintaxe, uma demonstração do código desse post funcionando pode ser vista aqui.

Caso esteja interessado nas outras funcionalidades que serão adicionadas ao Harmony, você pode conferir a tabela de compatibilidade com os browsers, compilers e node aqui.

Veja outros artigos sobre Front-end