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!
Agora escrito em com arrow function
hello = () => {
return "Hello World!";
}
hello() // Hello World!
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!
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
Agora escrito em com arrow function
sum = (a, b) => {
return a + b
}
sum(10,20) // 30
Podemos deixar mais curta ainda
sum = (a, b) => a + b
sum(10,20) // 30
Se tivermos apenas um parâmetro, podemos escrever sem os parênteses ()
, exemplo:
soma10 = a => a + 10
soma10(20) // 30
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"}
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 }
];
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]
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]
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
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);
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);
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
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
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 ]
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
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)
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)
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 propriedadetarget
, 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 usarthis
. 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
earguments
, 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)