Faaala galera! Já deu pra ver a pancada de funcionalidades que vieram junto com o ES6, não é? São tantos os novos recursos da linguagem, que eu não consegui falar nem sobre a metade deles no post ES6: O Guia Definitivo - Parte 1. Então antes de me estender muito, vamos seguir com as outras novidades!
Template Strings
Tenho certeza de que eu não sou o único a odiar as inevitáveis concatenações de strings no nosso código. Finalmente o ES6 trouxe consigo uma forma bem fácil de utilizar variáveis e funções dentro de strings:
Ou seja, a única coisa que precisamos fazer é colocar nosso código dentro do delimitador ${}
e Voilá! E como brinde, ainda gamos a possibilidade de criar um texto com várias linhas sem ter que concatenar e utilizar vários \n
.
Arrow functions
Um dos recursos mais amados do ES6 são as Arrow Functions, e não é a toa. Além de diminuirmos a quantidade de código escrita, nós também ganhamos o binding do escopo pai.
Mas vamos por partes…
Vejamos o seguinte exemplo, que mostra primeiramente a diferença na sintaxe:
Bem simples, não é? Note que não precisamos definir o retorno da função com essa sintaxe, mas se quisermos ter um corpo de bloco na nossa arrow function, podemos utilizar o delimitador {}
:
Outra vantagem de utilizarmos arrow functions é o fato de herdarmos o binding de this
do escopo mais próximo.
Mas o que isso significa?
Sabe quando estamos dentro de um callback e precisamos referenciar o this
do escopo pai? Nós não conseguimos fazer por padrão porque cada função no Javascript tem o seu próprio contexto.
Provavelmente a solucão mais famosa seja guardar o this
em uma variável temporária, geralmente chamada de self
:
Mas com o uso de arrow functions, esse código ficaria bem mais intuitivo, pois elas capturam o this
de seus contextos delimitadores. Logo, o this
dentro de uma arrow function se referencia ao escopo mais próximo.
O exemplo acima ficaria assim:
Destructuring assignments
Não é incomum precisarmos criar variáveis intermediárias para dados que vêm de uma estrutura como Arrays
ou Hashs
, quando o objetivo é o reaproveitamento de código.
Você com certeza já fez muitos códigos como os que seguem:
Não é lá muito elegante, mas ainda é melhor do que repetir toda a estrutura do seu Array/Objeto várias vezes para usar algum determinado valor. Mas com a chegada do ES6 nós ganhamos o versátil e poderoso recurso de Destructuring.
Destructuring é exatamente a ação de desestruturar o seu elemento e automaticamente criar variáveis com seus respectitivos valores. É como se estivéssemos extraindo os valores dos Arrays e Objetos.
Então vejamos o exemplo acima, já com o uso do Destructuring:
Beem melhor né? E o melhor de tudo é que você pode utilizar o Destructuring de várias formas, pois ele é super flexível. Confere aí mais alguns exemplos bacanas de utilização:
Orientação a objetos
Um dos recursos mais aguardados (e polêmicos) do ES6 é o suporte à Classes de objetos. A verdade é que o nosso querido Javascript sempre foi uma linguagem extremamente flexível, e por isso existem muitas formas de você representar um objeto, desde a declaração de um simples JSON até uma função de primeira classe.
Isso acontece porque, até o ES5, o Javascript se utilizava apenas da prototipação para implementar a Orientação a Objetos. Com isso, temos a possibilidade de instanciar uma simples função, e o próprio Javascript faz o binding da variável this
de acordo com o seu escopo, ganhando então o comportamento esperado de um objeto.
Vamos exemplificar como funciona a Orientação a Objetos por prototipação:
Note que estamos definindo um “rascunho” de como todo monstro deve ser, mesmo que possam ter métodos e atributos diferentes. E esses métodos diferenciados são definidos diretamente no objeto criado. Ou seja, podemos ter uma infinidade de monstros diferentes usando apenas um único protótipo inicial.
No nosso exemplo, onde temos apenas um tipo de cada monstro, a prototipação nos serve perfeitamente, mas se quisermos instanciar vários lobisomens por exemplo, teríamos que repetir o nosso código algumas vezes, ou utilizar a propriedade prototype
para termos um comportamento parecido com a Herança que estamos acostumados em outras linguagens.
Veja o seguinte exemplo, com o uso de prototype
:
Como vocês podem ver, além de chamar o construtor do “objeto pai”, precisamos substituir a propriedade prototype para termos acesso à todos os métodos do protótipo Monstro.
Se você não está familiarizado com o uso do prototype, ele nada mais é que uma propriedade que contém uma cópia do seu objeto pai. Por exemplo, quando instanciamos uma data com new Date()
, automaticamente a sua propriedade prototype é setada com Date.prototype
, fazendo com que nosso objeto “herde” os métodos e propriedades de Date
(para mais informações sobre o prototype, confira esse post no blog da Alura).
Suporte a Classes do ES6
O exemplo acima ficaria assim se fosse escrito na especificação do ES6, utilizando o suporte à Classes de objetos:
Tudo bem, o código pode não ter ficado menor, mas com certeza ficou mais legível.
O método constructor
é executado toda vez que um novo objeto é instanciado, e quando estamos instanciando uma classe “filha”, podemos usar o método super
para chamar o construtor do pai.
Note que estamos utilizando o prefixo _
antes dos nomes de atributos da classe Monstro
. Essa é apenas uma convenção para a definição de atributos privados da nossa classe, e por se tratar apenas de uma convenção, entende-se que a linguagem não vai fazer nenhum esforço para bloquear o acesso desses atributos de fora da nossa classe. Mas é um bom padrão para identificarmos se um atributo é privado ou não toda vez que batemos o olho nele.
E a parte boa é que ganhamos syntax sugar para os nossos Getters and Setters. Veja um exemplo:
Mesmo a classe não possuindo um atributo raio
, nós podemos utilizar códigos como circunferencia.raio
ou circunferencia.raio = x
graças às diretivas get
e set
na definição da nossa classe.
E se você está se perguntando “Mas onde estão os métodos estáticos?”, pode ficar tranquilo que o pessoal do TC39 não se esqueceu deles. Basta utilizar a diretiva static
antes da definição do método:
E vale lembrar duas últimas coisas sobre o Suporte a Classes do ES6:
-
A Declaração de classes não são hoisted como acontece com as funções. Ou seja, primeiro precisamos declarar nossa classe para só depois utilizá-la.
-
Todos os itens que foram abordardos nesse tópico não passam de sugar syntaxes para a prototipação padrão do ES5. Com isso temos uma maneira mais semântica de aplicar a orientação à objetos em nossos projetos através da declaração de classes, mas para o Javascript, tudo continua sendo a boa e velha prototipação. E isso não é necessariamente uma coisa ruim, porque nos dá a possibilidade de fazer um “mix” das duas abordagens =)
Com isso, acho que fechamos os principais recursos dessa incrível release do Javascript. Mas por incrível que pareça, ainda tem muito mais! Se você gostaria de aprender mais ainda sobre o ES6, recomendo esse link.
Bom galera, se vocês gostaram, não se esquecem de comentar aí embaixo, divulgar pros amigos, etc e tal. Deixem suas dúvidas, críticas e sugestões também.
Até a Próxima!!