DEV Community

Marcelo Cabral Ghilardi
Marcelo Cabral Ghilardi

Posted on

Arrow Functions (ou funções de seta)

Oi Pessoas

A nova (nem tão nova) versão de javascript ES6 trouxe as arrow functions. São uma nova forma de criar funções utilizando setas () => {}.

Poderia dizer que arrow functions substitui as functions, mas é bem mais que isso, é uma forma com sintaxe mais curta e elegante para criar funções. Além disso, nem sempre elas podem ser usadas.

Neste post, além de explicar a sintaxe, vou explicar as diferenças de escopo.

IMPORTANTE: Todos os exemplos podem ser executados no console do Navegador, no Chrome, tecle (Ctrl + Shift + J)

IMPORTANTE: Leia no final deste post onde não devem ser usadas as arrow functions

Sintaxe

A sintaxe para criação de arrow functions possui 3 partes () => {}:

  • Os parênteses (), que é por onde a função recebe os argumentos (assim como na function tradicional);
  • A seta =>, responsável pelo nome “arrow” function;
  • E as chaves {}, o bloco de código que representa o corpo da função.

Em algumas situações os parênteses () as chaves {} são opcionais

Antes, escrito com function tradicional

hello = function() {
  return "Hello World!";
}
hello() // Hello World!
Enter fullscreen mode Exit fullscreen mode

Agora escrito em com arrow function

hello = () => {
  return "Hello World!";
}
hello() // Hello World!
Enter fullscreen mode Exit fullscreen mode

A princípio não parece muita vantagem, apenas a sintaxe mais curta, a keyword function foi suprimida. Mas podemos deixar mais curta ainda

hello = () => "Hello World!";
hello() // Hello World!
Enter fullscreen mode Exit fullscreen mode

No exemplo acima, além de suprimir a keyword function, também foi suprimida a keyword return e as chaves {}

Sintaxe com parâmetros

Exemplo de uma função de soma, recebendo dois parâmetros e retornando a soma

Antes, escrito com function tradicional

sum = function (a, b) {
  return a + b
}
sum(10,20) // 30
Enter fullscreen mode Exit fullscreen mode

Agora escrito em com arrow function

sum = (a, b) => {
  return a + b
}
sum(10,20) // 30
Enter fullscreen mode Exit fullscreen mode

Podemos deixar mais curta ainda

sum = (a, b) => a + b
sum(10,20) // 30
Enter fullscreen mode Exit fullscreen mode

Se tivermos apenas um parâmetro, podemos escrever sem os parênteses (), exemplo:

soma10 = a => a + 10
soma10(20) // 30
Enter fullscreen mode Exit fullscreen mode

Retornar Objetos Literais

As arrow functions podem ser usadas para retornar uma expressão de objetos literais com uma sintaxe bem mais enxuta _(neste caso, o corpo sempre precisa ser colocado entre parênteses).

//Escrito com function tradicional
var setNameIdsEs5 = function setNameIds(id, name) {
  return {
    id: id,
    name: name
  };
};

//Escrito em com arrow function
var setNameIdsEs6 = (id, name) => ({ id: id, name: name });

console.log(setNameIdsEs6 (4, "Kyle"));   // Object {id: 4, name: "Kyle"}
Enter fullscreen mode Exit fullscreen mode

Manipulação de array com map ou reduce

Um caso comum para arrow functions é na manipulação de array, é comum que você precise mapear (map) ou reduzir (reduce) arrays

Assim que der, vou fazer um post sobre manipulação de arrays

Vamos criar um array simples

const smartPhones = [
  { name:'iphone', price:649 },
  { name:'Galaxy S6', price:576 },
  { name:'Galaxy Note 5', price:489 }
];
Enter fullscreen mode Exit fullscreen mode

Agora vamos criar uma matriz de objetos com apenas os preços dos smartphones

//Escrito com function tradicional
var pricesFunc = smartPhones.map(function(smartPhone) {
  return smartPhone.price;
});

console.log(pricesFunc); // [649, 576, 489]


//Escrito em com arrow function
const pricesArrow = smartPhones.map(smartPhone => smartPhone.price);

console.log(pricesArrow); // [649, 576, 489]
Enter fullscreen mode Exit fullscreen mode

Outro exemplo, agora usando o método filter dos arrays

const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];

//Escrito com function tradicional
var divisibleByThrreeES5 = array.filter(function (v){
  return v % 3 === 0;
});

//Escrito em com arrow function
const divisibleByThrreeES6 = array.filter(v => v % 3 === 0);

console.log(divisibleByThrreeES6); // [3, 6, 9, 12, 15]
Enter fullscreen mode Exit fullscreen mode

Um exemplo com reduce, neste caso a soma de todos elementos

var arr = [5, 6, 13, 0, 1, 18, 23];

var sum = arr.reduce((a, b) => a + b);  
console.log(sum ); // 66
Enter fullscreen mode Exit fullscreen mode

Promises e Callbacks

Códigos que usam promises e chamadas assincronas (callbacks) geralmente possuem uma grande quantidade de function e return

Assim que der, vou fazer um post sobre Promises

Se escrevermos com funções modernas, nós atribuímos nossas callbacks às promises retornadas, formando uma cadeia de promise:

//Escrito com function tradicional
doSomething().then(function(result) {
  return doSomethingElse(result);
})
.then(function(newResult) {
  return doThirdThing(newResult);
})
.then(function(finalResult) {
  console.log('Got the final result: ' + finalResult);
})
.catch(failureCallback);
Enter fullscreen mode Exit fullscreen mode

Os argumentos para then são opcionais, e catch(failureCallback) é uma abreviação para then(null, failureCallback).
Agora, escrevendo o mesmo código com arrow functions:

//Escrito em com arrow function
doSomething()
.then(result => doSomethingElse(result))
.then(newResult => doThirdThing(newResult))
.then(finalResult => {
  console.log(`Got the final result: ${finalResult}`);
})
.catch(failureCallback);

Enter fullscreen mode Exit fullscreen mode

Particularmente, eu vejo o código em arrow functions muito mais simples para ler, além de mais elegante.

Podemos substituir todas as function por arrow function? NÃO

Poderíamos pensar que sim, mas não é bem assim, um dos principais motivos é o uso da palavra chave this.

Tenho um post onde explico sobre this

Diferente das function tradicionais, você não consegue injetar o this em arrow functions. Isso mesmo!

Se o this for usado dentro de uma arrow functions, esse this vai fazer referência ao objeto que ele já era referência no momento da criação da arrow function.

Vamos comparar, se criarmos um objeto com dois métodos, ambos métodos acessam this, um criado por function tradicional (correrFunc) e outro por arrow function (correrArrow).

pessoa = {
    nome: "Cebolinha",

    correrFunc: function() {
         console.log(this);
    },

    correrArrow: () => console.log(this)
}
pessoa.correrFunc() // => Object {nome: "Cebolinha", correrFunc:, correrArrow: }
pessoa.correrArrow() // => Window
Enter fullscreen mode Exit fullscreen mode

O método correrFunc retorna o próprio objeto e o método correrArrow retorna o objeto window. Isso ocorre porque no momento da criação do objeto, o escopo era do window (mesmo que usasse o 'use strict', veja meu post sobre this).

Arrow functions não tem acesso aos arguments

Pelo mesmo motivo do this, arrow functions não tem acesso aos arguments, isto é, teria acesso a arguments globais e não ao contexto local.

// Traditional function
var crescente = function() {
  return Array.from(arguments).sort((a, b) => a > b)
}
crescente(3,2,5,1,4,8,7,6); // Array [ 1, 2, 3, 4, 5, 6, 7, 8 ]


// Arrow function
var crescente = () => {
  return Array.from(arguments).sort((a, b) => a > b);
}
crescente(3,2,5,1,4,8,7,6); // Exception: ReferenceError: arguments is not defined
Enter fullscreen mode Exit fullscreen mode

Uma solução para usar arrow functions neste caso seria usar o spread operator, para criar uma função com REST params, desta forma

// Arrow function com spread operator
var crescente = (...arguments) => {
  return Array.from(arguments).sort((a, b) => a > b);
}
crescente(3,2,5,1,4,8,7,6); // Array [ 1, 2, 3, 4, 5, 6, 7, 8 ]
Enter fullscreen mode Exit fullscreen mode

Arrow functions não podem ser usadas como constructor

As arrow functions não podem ser usadas como construtores, não pode usar o operador new para criar uma nova instância de objeto.

// Traditional function
const ConstrutorFunc = function () {};
new ConstrutorFunc(); // Object { }

// Arrow function
const ConstrutorArrow = () => {};
new ConstrutorArrow(); // Constructor is not a constructor
Enter fullscreen mode Exit fullscreen mode

Mais um exemplo de quando NÃO devemos usar arrow functions

Outro caso que é bem comum são em eventos, o método addEventListener sempre injeta o this, mas para acessar o this precisamos usar function tradicional.

Veja o exemplo:

const $input = document.querySelector('input[type="text"]')
$input.addEventListener('input', function () {
  console.log('value:', this.value)
}, false)
Enter fullscreen mode Exit fullscreen mode

Assumindo que exista um campo input, ao começar a digitar algo dentro desse campo, podemos ver o valor do campo sendo exibido no console, pois o this dentro da função passada como listener do evento é injetado pelo addEventListener, fazendo referência ao objeto do DOM ao qual o evento foi atrelado.

Agora tente usar uma arrow functions no lugar da function tradicional

const $input = document.querySelector('input[type="text"]')
$input.addEventListener('input', () => {
  console.log('value:', this.value)
}, false)
Enter fullscreen mode Exit fullscreen mode

Nesse caso, veja que o valor exibido no console é sempre undefined (a menos que exista um objeto no escopo em que a função foi criada, e esse objeto tenha uma propriedade value).

Considerações

  • se a função que você tem não depende de this, você pode substituir por arrow functions sem problemas;

  • evite usar o this. No caso do exemplo do evento, toda função listener de um evento recebe um objeto de evento, com uma propriedade target, que faz referência ao elemento que recebeu o evento. Use esse objeto se precisar manipular ou fazer qualquer coisa com o elemento que disparou o evento, ao invés de usar this. Dessa forma você evita os problemas vistos acima;

  • Arrow functions não tem acesso aos arguments como as functions tradicionais.

  • Arrow functions não podem ser usadas como construtor, não podemos aplicar o operador new;

  • Exceto pelo this, new e arguments, todas as demais functions tradicionais podem ser trocadas por arrow functions.

Perdi Algo?

Por favor, me diga se eu esqueci de algo!!

Obrigado a Vinicius Da Mata Pickrodt pela correção deste post.

Referências

- https://raphaelfabeni.com/es6-arrow-functions/
- https://medium.com/@raphalima8/arrow-functions-declara%C3%A7%C3%A3o-funcionamento-escopos-e-o-valor-de-this-9cb6449bca31
- https://blog.da2k.com.br/2019/01/07/javascript-tudo-sobre-arrow-functions/
- https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/
- https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Functions/Arrow_functions
- https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Guide/Usando_promises
- https://medium.com/@raphalima8/arrow-functions-declara%C3%A7%C3%A3o-funcionamento-escopos-e-o-valor-de-this-9cb6449bca31
- https://medium.com/frontend-quest/arrow-functions-vs-functions-9048ec12b5c6

Top comments (0)