Let permite criar declarações limitadas a qualquer bloco, o que é chamado de escopo de bloco, diferente do var, que fornece escopo de função.
var x = 3;
var y = 1;
if(x === 3) {
let x = 5; // O escopo é dentro do bloco
var y = 2; // O escopo é dentro da função
console.log(x); // 5
console.log(y); // 2
}
console.log(x); // 3
console.log(y); // 2
Um dos cenários ideais para utilização do let é na declaração do laço de repetição for.
for(let i = 0; i < 5; i++) {
console.log(i); // 0, 1, 2, 3, 4
}
console.log(i); // ReferenceError: i is not defined(…)
Const representa uma referência constante para um valor fixo. Isso não significa que o valor é imutável, apenas que a variável constante não pode ser alterada ou retribuída.
const PI = 3.14;
console.log(PI); // 3.14
PI = 100; // TypeError: Assignment to constant variable.(…)
Const também é uma variável de escopo de bloco!
{
const PI = 3.14;
console.log(PI); // 3.14
}
console.log(PI); // ReferenceError: PI is not defined(…)
Let e const variam da forma tradicional de hoisting de variáveis e funções. Ambos estão hoistados, mas não podem ser acessados antes das suas declarações, por causa da Temporal Dead Zone.
console.log(nome); // ReferenceError: nome is not defined(…)
let nome = 'Gabriel';
console.log(sobrenome); // Undefined
var sobrenome = 'Medina';
let adicao = function(a, b) {
return a + b;
};
// Implementação com Arrow Function
let adicao = (a, b) => a + b;
Arrow functions são uma notação short-hand para escrever funções em ES6. Sua definição consiste em uma lista de parâmetros ( ... ), seguido de um => e o corpo da função.
let frutas = ['maçã', 'banana', 'laranja'];
let frutas_plural = frutas.map(fruta => {
return fruta + 's';
});
console.log(frutas_plural); // ['maçãs', 'bananas', 'laranjas']
Note que no exemplo anterior nós implementamos a Arrow function com um "corpo conciso", que não precisa de declaração de retorno explícita. Mas podemos implementar também com o "corpo de bloco".
Arrow functions não só reduzem o tamanho do código. Também estão relacionados ao comportamento do binding do this.
O comportamento das Arrow functions com o this é diferente do das funções normais. Cada função no JavaScript define seu próprio contexto de this, mas as Arrow functions capturam o this do seu contexto delimitador.
function Pessoa() {
this.idade = 0;
setInterval(function envelhecer() {
// Em modo não estrito, a função envelhecer() define `this`
// como o objeto global, que é diferente ao `this`
// definido pelo construtor de Pessoa().
this.idade++;
}, 1000);
}
var gabriel = new Pessoa();
No ECMAScript 3/5, esse problema era corrigido ao atribuir o valor de this para uma variável.
function Pessoa() {
var self = this;
self.idade = 0;
setInterval(function envelhecer() {
// O callback se refere à variável `self` cujo valor
// é o objeto esperado
self.idade++;
}, 1000);
}
var gabriel = new Pessoa();
Arrow functions capturam o valor de this do contexto delimitador, logo, o código a seguir funciona como esperado.
function Pessoa() {
this.idade = 0;
setInterval(() => {
// `this` se refere corretamente ao objeto pessoa
this.idade++;
}, 1000);
}
var gabriel = new Pessoa();
ES6 permite que você defina parâmetros default nas definições de funções.
let getPrecoFinal = (preco, imposto = 0.7) => preco + preco * imposto;
getPrecoFinal(500); // 850
function Pessoa(nome, idade = 0, status = true) {
this.nome = nome;
this.idade = idade;
this.status = status;
}
var gabriel = new Pessoa('Gabriel');
O operador ... é chamado de operador spread ou rest, dependendo de como e onde é usado. Quando usado com qualquer iterável, ele age como "spread" em elementos individuais.
let arr = [1, 2, 3];
console.log(...arr); // 1 2 3
O outro uso comum de ... é juntar uma série de valores em uma array. Nesse caso, o operador é chamado de "rest".
function foo(...args) {
console.log(args);
}
foo(1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]
ES6 permite que se declare objetos literais com uma sintaxe abreviada para inicializar propriedades de variáveis e definir métodos das funções.
Também permite ter índices de propriedades computadas em uma definição de objeto literal.
function getCarro(fabricante, modelo, valor) {
return {
// com a sintaxe abreviada de
// valor da propriedade, você
// pode omitir o valor da propriedade
// se o índice casa com o nome
// da variável
fabricante, // o mesmo que fabricante: fabricante
modelo, // o mesmo que modelo: modelo
valor, // o mesmo que valor: valor
// valores computados agora funcionam
// como objetos literais
['fabricante' + fabricante]: true,
// sintaxe de abreviação de definição
// de método omite a keyword `function`
// e a vírgula
depreciar() {
this.valor -= 2500;
}
};
}
let carro = getCarro('Kia', 'Sorento', 40000);
// output: {
// fabricante: 'Kia',
// modelo:'Sorento',
// valor: 40000,
// fabricanteKia: true,
// depreciar: function()
// }
function foo() {
return [1, 2, 3];
}
let arr = foo(); // [1,2,3]
let [a, b, c] = foo();
console.log(a, b, c); // 1 2 3
function bar() {
return {
x: 4,
y: 5,
z: 6
};
}
let { x: a, y: b, z: c } = bar();
console.log(a, b, c); // 4 5 6
Desestruturamento ajuda a evitar a necessidade de variáveis temporárias quando lida-se com objetos e arrays.
var pai = {
foo() {
console.log("Sou o Pai");
}
}
var filho = {
foo() {
super.foo();
console.log("Sou o Filho");
}
}
Object.setPrototypeOf(filho, pai);
filho.foo(); // Sou o Pai, Sou o Filho
ES6 permite que use o método super em objetos (sem classe) em protótipos.
let user = 'Medina';
console.log(`Olá ${user}!`); // Olá Medina!
ES6 introduz uma forma mais fácil ainda de adicionar interpolação analisada automaticamente.
console.log(`string text line 1
string text line 2`);
<a href="#" class="btn btn--info" title="Informações adicionais para melhorar a experiência do usuário">Mais informações</a>
<script>
let element = document.querySelector('.btn--info');
element.addEventListener('click', function(e) {
e.preventDefault();
document
.querySelector('body')
.insertAdjacentHTML('beforeend',
`<div class="modal">
<div class="modal__content">
<p>${this.title}</p>
</div>
</div>`
);
});
}
</script>
Com toda certeza você já precisou montar um template HTML em seus scripts. Já passou por isso? As notícias são boas pra você!
let apelidos = ['zé', 'bobão', 'cabeçudo'];
apelidos.size = 3;
for (let apelido of apelidos) {
console.log(apelido); // zé, bobão, cabeçudo
}
for...of itera em objetos iteráveis, tipo arrays.
for...in itera sobre todas as propriedades enumeráveis do objeto.
for (let apelido in apelidos) {
console.log(apelido); // 0, 1, 2, size
}
ES6 introduz uma nova sintaxe para classes. Entretanto, as classes não são um novo modelo de herança da orientação a objetos. Elas apenas servem como sintaxe sugar sobre as heranças existentes de prototype do JavaScript.
Devemos olhar para as classes do ES6 apenas como uma nova sintaxe para se trabalhar com prototypes e funções construtoras que usaríamos no ES5.
class Tarefa {
constructor() {
console.log('Tarefa instanciada!');
}
mostrarId() {
console.log(23);
}
static carregarTodas() {
console.log('Carregando todas as tarefas..');
}
}
console.log(typeof Tarefa); // function
let tarefa = new Tarefa(); // Tarefa instanciada!
tarefa.mostrarId(); // 23
Tarefa.carregarTodas(); // Carregando todas as tarefas..
class Carro {
constructor() {
console.log('Criando um novo carro');
}
}
class Porsche extends Carro {
constructor() {
super();
console.log('Criando um Porsche');
}
}
let c = new Porsche(); // Criando um novo carro, Criando um Porsche
Ainda podemos utilizar extends e super em classes!
Paramos por aqui?
O JavaScript esta evoluindo e as novidades são fantásticas.
Quer continuar aprendendo mais?
Nem tudo sobre as novidades do ES6 foi falado aqui, então segue o link: