Dez exemplos de funcionalidades das ES6

visualizações Publicado em: 09/11/2017

Crédito: essa matéria é uma tradução e foi escrita por Lukasz Kyc. URL do original: Blog Pragmatists

Introdução

Embora as especificações para ES6 não sejam tão recentes eu acredito que muitos desenvolvedores ainda não estão familiarizados com elas. A razão para isso talvez tenha sido o suporte precário oferecido pelos navegadores logo após o lançamento das especificações. Atualmente, passados mais de 2 anos, a maioria dos navegadores modernos já suportam as funcionalidades das ES6. Caso você ou seus clientes, não usem a versão mais recente de um navegador é possível, durante o processo de construção da aplicação, servir os códigos escritos ES6 como se fossem ES5 usando transpilers, tal como o Babel. Assim, é hora de dar um passo à frente e aprender ES6.

Nesta matéria é minha intenção mostrar as mais importantes funcionalidades da ES6 de uma maneira suscinta, de modo que ao chegar ao final da matéria você esteja em condições de aplicar os fundamentos das ES6 em um projeto real. Não se trata de um guia completo ou uma documentação para consulta e sim de uma amostra, com a finalidade de motivá-lo a continuar e aprofundar seus estudos de ES6.

Vamos começar

1. Palavras-chave const e let

A palavra-chave const destina-se a declarar valores constantes (finalmente!) e a palavra-chave let destina-se a declarar valores variáveis. Isso é fantástico, mas já existe uma palavra-chave para definir variáveis em JavaScript certo? Certíssimo, mas variáveis declaradas com uso da palavra-chave var ficam confinadas no escopo da função na qual são declaradas e "hoisted to the top" (Nota do tradutor: se você não sabe o que é isso, consulte essa página do glossário da MDN - link abre em nova aba). Isso significa que uma variável pode ser usada antes de ser declarada. Variáveis declaradas com uso das palavras-chave const e let ficam confinadas no escopo do bloco ( limitado por { } ) no qual são declaradas e não podem ser usadas antes de serem declaradas.

O exemplo mostrado a seguir esclarace o escopo das variáveis x, y e z declaradas com uso das palavras-chave mostradas.

Código

function f() {
var x = 1
let y = 2
const z = 3
{
  var x = 100
  let y = 200
  const z = 300
  console.log('x in block scope is', x)
  console.log('y in block scope is', y)
  console.log('z in block scope is', z)
}
  console.log('x outside of block scope is', x)
  console.log('y outside of block scope is', y)
  console.log('z outside of block scope is', z)
}

f()

Saída

x in block scope is 100 
y in block scope is 200 
z in block scope is 300 
x outside of block scope is 100 
y outside of block scope is 2 
z outside of block scope is 3 

2. Funções helper para arrays

Novas funções helper para arrays foram criadas pela ES6 com a finalidade de facilitar a manipulação de arrays. Quantas vezes você precisou desenvolver código JavaScript para realizar tarefas tais como filtrar, verificar se um ou mais elementos satisfazem determinada condição ou até mesmo para realizar conversões? Provavelmente muitas vezes. Novas funcionalidades foram criadas para realizar tais tarefas para você. Na minha opinião as funções mostradas a seguir são as mais valiosas:

forEach

Executa uma função para cada um dos elementos de um array. O argumento dessa função helper é cada um dos elementos do array.

Código

var colors = ['red', 'green', 'blue']

function print(val) {
  console.log(val)
}

colors.forEach(print)

Saída

red 
green 
blue 

map

Cria um array contendo o mesmo número de elementos de um determinado array. Os elementos do array criado são definidos por uma função, ou seja, converte o array original em outro, renomeando seus elementos.

Código

var colors = ['red', 'green', 'blue']

function capitalize(val) {
    return val.toUpperCase()
}

var capitalizedColors = colors.map(capitalize)

console.log(capitalizedColors)

Saída

["RED","GREEN","BLUE"] 

filter

Cria um array contendo um subconjunto dos elementos do array original. O subconjunto de elementos do novo array é determinado por uma função que retorna true ou false quando verifica uma determinada condição para cada elemento do array original.

Código

var values = [1, 60, 34, 30, 20, 5]

function lessThan20(val) {
    return val < 20
}

var valuesLessThan20 = values.filter(lessThan20)

console.log(valuesLessThan20)

Saída

[1,5] 

find

Encontra o primeiro elemento de um array que satisfaz determinada condição imposta por uma função que retorna true ou false para cada elemento do array original.

Código

var people = [
  {name: 'Jack', age: 50},
  {name: 'Michael', age: 9}, 
  {name: 'John', age: 40}, 
  {name: 'Ann', age: 19}, 
  {name: 'Elisabeth', age: 16}
]

function teenager(person) {
    return person.age > 10 && person.age < 20
}

var firstTeenager = people.find(teenager)

console.log('First found teenager:', firstTeenager.name)

Saída

First found teenager: Ann 

every

Verifica cada elemento de um array para uma determinada condição imposta por uma função que retorna true ou false.

Código

var people = [
  {name: 'Jack', age: 50},
  {name: 'Michael', age: 9}, 
  {name: 'John', age: 40}, 
  {name: 'Ann', age: 19}, 
  {name: 'Elisabeth', age: 16}
]

function teenager(person) {
    return person.age > 10 && person.age < 20
}

var everyoneIsTeenager = people.every(teenager)

console.log('Everyone is teenager: ', everyoneIsTeenager)

Saída

Everyone is teenager:  false

some

Verifica se algum elemento de um array satisfaz determinada condição imposta por uma função que retorna true ou false.

Código

var people = [
  {name: 'Jack', age: 50},
  {name: 'Michael', age: 9}, 
  {name: 'John', age: 40}, 
  {name: 'Ann', age: 19}, 
  {name: 'Elisabeth', age: 16}
]

function teenager(person) {
    return person.age > 10 && person.age < 20
}

var thereAreTeenagers = people.some(teenager)

console.log('There are teenagers:', thereAreTeenagers)

Saída

There are teenagers: true

reduce

Esta função admite dois parâmetros e se destina a iterar sobre cada elemento de um array executando uma função callback. O primeiro parâmetro é a função callback que acumula valores resultado de uma operação realizada a cada iteração e o segundo parâmetro é o valor inicial da acumulação.

Código

var array = [1, 2, 3, 4]

function sum(acc, value) {
  return acc + value
}

function product(acc, value) {
  return acc * value
}

var sumOfArrayElements = array.reduce(sum, 0)
var productOfArrayElements = array.reduce(product, 1)

console.log('Sum of', array, 'is', sumOfArrayElements)
console.log('Product of', array, 'is', productOfArrayElements)

Saída

Sum of [1,2,3,4] is 10 
Product of [1,2,3,4] is 24 

3. Arrow functions

A sintaxe para escrita até mesmo das mais simples funções JavaScript, tais como, somar ou multiplicar, é bastante verbosa e complexa. Existe uma maneira mais simples de se escrever funções? Sim, experimente as arrow functions. ( funções de setas? eca! ).

Código

var array = [1, 2, 3, 4]

const sum = (acc, value) => acc + value
const product = (acc, value) => acc * value

var sumOfArrayElements = array.reduce(sum, 0)
var productOfArrayElements = array.reduce(product, 1)

Arrow functions podem ser escritas inline. Elas realmente simplificam o código:

Código

var array = [1, 2, 3, 4]

var sumOfArrayElements = array.reduce((acc, value) => acc + value, 0)
var productOfArrayElements = array.reduce((acc, value) => acc * value, 1)

Arrow functions podem, também, ser mais verbosas e ocupar várias linhas de código:

Código

var array = [1, 2, 3, 4]

const sum = (acc, value) => {
  const result = acc + value
  console.log(acc, ' plus ', value, ' is ', result)
  return result
}

var sumOfArrayElements = array.reduce(sum, 0)

4. Classes

Que desenvolvedor Java não estranhou a falta das classes quando resolveu criar um projeto JavaScript? Quem não prefere herança explícita, tal como em Java, a ter que criar código mágico para herança prototipada? Ainda que contrariando alguns desenvolvedores, classes JavaScript foram criadas na ES6. Elas não mudaram o conceito de herança. Elas são na verdade "syntactic sugar" para herança prototipada

Código

class Point {
    constructor(x, y) {
        this.x = x
        this.y = y
    }

    toString() {
        return '[X=' + this.x + ', Y=' + this.y + ']'
    }
}

class ColorPoint extends Point {
    static default() {
        return new ColorPoint(0, 0, 'black')
    }

    constructor(x, y, color) {
        super(x, y)
        this.color = color
    }

    toString() {
        return '[X=' + this.x + ', Y=' + this.y + ', color=' + this.color + ']'
    }
}

console.log('The first point is ' + new Point(2, 10))
console.log('The second point is ' + new ColorPoint(2, 10, 'green'))
console.log('The default color point is ' + ColorPoint.default())

Saída

The first point is [X=2, Y=10] 
The second point is [X=2, Y=10, color=green] 
The default color point is [X=0, Y=0, color=black] 

5. Objeto literais incrementados

Com ES6 é muito mais fácil:

  • atribuir campos à variáveis de mesmo nome
  • escrever funções
  • efetuar (cálculos) propriedades dinâmicas

Código

const color = 'red'
const point = {
  x: 5,
  y: 10,
  color,
  toString() {
    return 'X=' + this.x + ', Y=' + this.y + ', color=' + this.color
  },
  [ 'prop_' + 42 ]: 42
}

console.log('The point is ' + point)
console.log('The dynamic property is ' + point.prop_42)

Saída

The point is X=5, Y=10, color=red 
The dynamic property is 42

6. Template strings

Eu acredito que poucos gostam da sintaxe para strings extensas e para a concatenação de variáveis. Felizmente as ES6 criaram um método muito simples para se criar templates para strings com placeholders para variáveis.

Código

function hello(firstName, lastName) {
  return `Good morning ${firstName} ${lastName}! 
How are you?`
}

console.log(hello('Jan', 'Kowalski'))

Saída

Good morning Jan Kowalski! 
How are you?

7. Argumentos default para funções

É tarefa entediante definir todos os parâmetros de uma função? Use valores default.

Código

function sort(arr = [], direction = 'ascending') {
  console.log('I\'m going to sort the array', arr, direction)
}

sort([1, 2, 3])
sort([1, 2, 3], 'descending')

Saída

I'm going to sort the array [1,2,3] ascending 
I'm going to sort the array [1,2,3] descending

8. Rest and spread operators

Spread

Possibilita extrair os conteúdos de um array ou de um objeto e transformá-los em um elemento simples.

Exemplo  —  criar uma "cópia" de um array:

Código

var array = ['red', 'blue', 'green']
var copyOfArray = [...array]

console.log('Copy of', array, 'is', copyOfArray)
console.log('Are', array, 'and', copyOfArray, 'same?', array === copyOfArray)

Saída

Copy of ["red","blue","green"] is ["red","blue","green"] 
Are ["red","blue","green"] and ["red","blue","green"] same? false

Exemplo  —  combinar arrays:

Código

var defaultColors = ['red', 'blue', 'green']
var userDefinedColors = ['yellow', 'orange']

var mergedColors = [...defaultColors, ...userDefinedColors]

console.log('Merged colors', mergedColors)

Saída

Merged colors ["red","blue","green","yellow","orange"]

Rest

Precisa atrelar os primeiros parâmetros de uma função a variáveis e os demais parâmetros a um array? Isso agora é possível, e muito fácil de se conseguir.

Código

function printColors(first, second, third, ...others) {
  console.log('Top three colors are ' + first + ', ' + second + ' and ' + third + '. Others are: ' + others)
}
printColors('yellow', 'blue', 'orange', 'white', 'black')

Saída

Top three colors are yellow, blue and orange. Others are: white,black

9. Destructuring

array

Possibilita extrair elementos de um array e atribuí-los à variáveis.

Código

function printFirstAndSecondElement([first, second]) {
    console.log('First element is ' + first + ', second is ' + second)
}

function printSecondAndFourthElement([, second, , fourth]) {
    console.log('Second element is ' + second + ', fourth is ' + fourth)
}

var array = [1, 2, 3, 4, 5]

printFirstAndSecondElement(array)
printSecondAndFourthElement(array)

Saída

First element is 1, second is 2 
Second element is 2, fourth is 4

object

Possibilita extrair propriedades de um objeto e atribuí-las à variáveis com o mesmo nome da propriedade.

Código

function printBasicInfo({firstName, secondName, profession}) {
	console.log(firstName + ' ' + secondName + ' - ' + profession)
}

var person = {
  firstName: 'John',
  secondName: 'Smith',
  age: 33,
  children: 3,
  profession: 'teacher'
}

printBasicInfo(person)

Saída

John Smith - teacher

10. Promises

Promises prometem (concordo, é estranho esse termo né?) que o resultado de tarefas que demandam longo tempo para serem executadas ou que tenham sido adiadas serão entregues posteriormente. Promise tem dois canais: um para resultados e outro para potenciais erros. Para receber o resultado de uma promessa defini-se uma função callback como parâmetro da função then. Para tratar erros passa-se a função callback como parâmetro da função catch.

No exemplo mostrado a seguir a saída será diferentente a cada execução pois a função chama um número randômico a cada execução.

Código

function asyncFunc() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
          const result = Math.random();
          result > 0.5 ? resolve(result) : reject('Oppps....I cannot calculate')
        }, 1)
    });
}

for (let i=0; i<10; i++) {
	asyncFunc()
    	.then(result => console.log('Result is: ' + result))
    	.catch(result => console.log('Error: ' + result))
}

Saída

Result is: 0.7930997430022211 
Error: Oppps....I cannot calculate 
Result is: 0.6412258210597288 
Result is: 0.7890325910244533 
Error: Oppps....I cannot calculate 
Error: Oppps....I cannot calculate 
Result is: 0.8619834683310168 
Error: Oppps....I cannot calculate 
Error: Oppps....I cannot calculate 
Result is: 0.8258410427354488

Sumário

Espero que você tenha gostado do artigo. Se quiser praticar e acelerar o processo de aprendizagem, use uma ferramenta online hospedada em https://es6console.com/ (abre em nova janela).

Para mais informações consulte:

Meus agradecimentos a Krzysztof Jelski pelo feddback.

topo