Falando um pouco sobre Arrow Functions

front-end

tags:

  • javascript
  • ES6
  • arrow functions

Postado em 01/05/2018

Olá! Seja bem vindo(a) ao post sobre Arrow Functions, vou falar um pouco sobre essa feature que veio com o ES6. Eu sei que esse assunto já não é mais uma “novidade”, pois esse tipo de função já vem sendo usada largamente, mas mesmo assim decidi falar sobre isso nessa minha primeira postagem com o tema JavaScript, pois apesar de as Arrow Functions ajudarem muito na produtividade, em alguns momentos seu funcionamento ainda pode gerar dúvidas.

Primeiramente vou começar citando esse resumo da MDN:

Uma expressão arrow function possui uma síntaxe mais curta quando comparada com expressões de função (function expressions) e não faz o bind do this. Arrow functions sempre são anônimas.

Esse resumo define exatamente as principais vantagens da Arrow Function: sintaxe mais curta e não fazer bind do this (o famoso escopo léxico). Mas o que isso significa na prática? Vou falar um pouco mais sobre cada um.

Sintaxe mais curta

Traduzindo para uma frase mais completa, tornar a sintaxe mais curta significa digitar menos comandos e ter o mesmo resultado de um comando originalmente maior. Resumindo: digitar menos. Tem gente que chama isso de tornar a linguagem menos verbosa, ou prefere usar o termo syntax sugar (ou até açúcar sintático). Para podermos comparar, vou usar um exemplo simples, uma função que recebe dois números e retorna a soma deles.

Na versão clássica:

function somaClassica(a, b) {
  return a + b
}
console.log(somaClassica(1, 5)) //6

Agora a versão mais curta possível com Arrow Function:

const somaArrow = (a, b) => a + b

console.log(somaArrow(a, b)) //6

Repare que eu disse “versão mais curta possível”, por que existem algumas maneira diferentes de usarmos a Arrow Function, dependendo da quantidade de parâmetros e do código que estará dentro da função.

Funções sem parâmetros

function oi() {
  return "Oi"
}

console.log(oi()) //'Oi'
const oiArrow = () => "Oi"

console.log(oiArrow()) //'Oi'

Para funções sem parâmetros, passamos os parênteses vazios.

Funções com apenas 1 parâmetro

function oi(nome) {
  return "Oi, " + nome
}

console.log(oi("Renato")) //'Oi, Renato'
const oiArrow = nome => "Oi, " + nome

console.log(oiArrow("Renato")) //'Oi, Renato'

Funções com vários parâmetros

function oi(nome, sobrenome) {
  return "Oi, " + nome + " " + sobrenome
}

console.log(oi("Renato", "Freire")) //'Oi, Renato Freire'
const oiArrow = (nome, sobrenome) => "Oi, " + nome + " " + sobrenome

console.log(oiArrow("Renato")) //'Oi, Renato Freire'

Quando a função recebe dois ou mais parâmetros os parênteses são obrigatórios.

Quando a função possui apenas uma expressão:

function quadrado(n) {
  return n * n
}

console.log(quadrado(3)) //9
const quadradoArrow = n => n * n

console.log(quadradoArrow(3)) //9

Como o corpo da função é uma expressão simples, não foi necessário usar as chaves “{}” e o valor da expressão é automaticamente retornado, sem a necessidade de usar o “return”.

Quando a função possui um bloco de código:

function quadrado(n) {
  let q = n * n
  return "O quadrado de " + n + " é " + q
}

console.log(quadrado(3)) //'O quadrado de 3 é 9'
const quadradoArrow = n => {
  let q = n * n
  return "O quadrado de " + n + " é " + q
}

console.log(quadradoArrow(3)) //O quadrado de 3 é 9

Nesse caso, o corpo da função é um bloco de código, então o uso das chaves “{}” é obrigatório. Também não podemos esquecer de que precisamos usar o “return” se quisermos retornar algum valor.

Resumindo a questão de parâmetros e corpo da função:

Função sem parâmetros, parênteses vazios:

const arrow1 = () => "Oi"

Função com um parâmetro, parênteses não são necessários:

const arrow2 = a => a * a

Função com vários parâmetros, os parênteses são obrigatórios

const arrow3 = (a, b) => a + b

Corpo da função com um bloco de código, obrigatório o uso de chaves “{}” e de return se algum valor precisar ser retornado

const arrow4 = a => {
  let q = a * a
  return "O resultado é: " + q
}

Corpo da função é uma única expressão, não é obrigatório o uso de chaves e o resultado da expressão é retornado automaticamente.

const arrow5 = a => a * a

Apenas para deixar claro, mesmo que o corpo da função seja uma única expressão, se as chaves forem usadas, o resultado não é retornado automaticamente.

const arrow6 = a => {
  return a * a
}

Mais uma observação sobre as Arrow Functions: elas são sempre anônimas, isso significa que você não pode dar nomes à uma função desse tipo. Contudo, no Javascript é possível salvar uma função dentro de uma variável, e esse comportamento se aplica as Arrow Functions também.

O escopo léxico

Apesar do nome incomum, o conceito é relativamente simples. Bem resumidamente, o this da Arrow Function é baseado em onde a função foi declarada. Não vou entrar em muitos detalhes sobre essa questão, pois seria necessário explicar alguns outros conceitos, mas geralmente temos problemas com o this em funções usadas como callback e funções assíncronas em geral. Para corrigir esses problemas, são usados alguns artifícios, como .bind ou criar uma variável para salvar o this e passar como parâmetro.

Vou criar um exemplo bem básico, com um setTimeout para ilustrar:

let pessoa = {
  camisa: "vermelha",
  calca: "azul",
  sapato: "preto",

  vestuario: function () {
    console.log(
      "Eu estou vestindo uma camisa " +
        this.camisa +
        ", uma calça " +
        this.calca +
        " e um sapato " +
        this.sapato
    )
  },
}

Se chamarmos a função pessoa.vestuario() o retorno será: Eu estou vestindo uma camisa vermelha, uma calça azul e um sapato preto

Tudo funcionou certinho até agora. Mas se adicionarmos o setTimeout na função pessoa.vestuario():

let pessoa = {
  camisa: "vermelha",
  calca: "azul",
  sapato: "preto",

  vestuario: function () {
    setTimeout(function () {
      console.log(
        "Eu estou vestindo uma camisa " +
          this.camisa +
          ", uma calça " +
          this.calca +
          " e um sapato " +
          this.sapato
      )
    }, 150)
  },
}

E novamente chamamos a função pessoa.vestuario(), teremos o seguinte resultado após 150 milisegundos: Eu estou vestindo uma camisa undefined, uma calça undefined e um sapato undefined Isso acontece por que a função é executada em um escopo diferente do objeto “Pessoa”.

Mas se usarmos uma Arrow Function no setTimeout, temos a função mantendo seu escopo:

let pessoa = {
  camisa: "vermelha",
  calca: "azul",
  sapato: "preto",

  vestuario: function () {
    setTimeout(() => {
      console.log(
        "Eu estou vestindo uma camisa " +
          this.camisa +
          ", uma calça " +
          this.calca +
          " e um sapato " +
          this.sapato
      )
    }, 150)
  },
}

Executando o pessoa.vestuario(), dessa vez temos o resultado esperado: Eu estou vestindo uma camisa vermelha, uma calça azul e um sapato preto

Mas como tudo na vida, existem exceções

As Arrow Functions são muito úteis e ajudam muito na hora de desenvolver, mas é importante saber como elas funcionam e entender que em determinadas situações elas não devem ser aplicadas, como por exemplo em funções que são usadas como handlers de eventos (quando usamos o addEventListener por exemplo).

Concluindo…

Apesar de serem bem simples de compreender, no começo as Arrow Functions podem confundir um pouco, principalmente na questão do escopo do this.
Pode até parecer que a síntaxe reduzida dela não ajude tanto, mas na prática é muito útil, pois não se trata apenas de reduzir a quantidade de caracteres digitados, elas dão mais fluidez na hora de transformar o que está no pensamento em código.
Depois de se acostumar esse tipo de função a leitura do código também fica bastante simplificada e até mais fácil de entender.

Então é isso pessoal. Esse é um pequeno resumo sobre Arrow Functions, vou deixar aqui alguns links que usei para aprender mais sobre elas antes de fazer esse post. Recomendo a leitura de todos eles:

Documentação da Mozilla

ES6: arrow functions em 5 minutos

Quando não usar Arrow Functions

Arrow Functions — Declaração, funcionamento, escopos e o valor de this

E esta página do livro Exploring ES6 publicado no Exploring JS

Se encontrar algum erro ou tiver alguma dúvida ou quiser acrescentar algum conhecimento neste post, por favor deixe um comentário :)

Compartilhe:

posts relacionados

Métodos do Array: map - Javascript

O método map em Javascript recebe uma função de callback e invoca ela para cada elemento do array, retornando um novo array.

ver post

Métodos do Array: slice - Javascript

O método slice em Javascript retorna uma cópia de uma parte de um array, delimitado pela posição inicial e final, sem modificar o array original.

ver post