Quando não usar Arrow Functions
Publicação: | Tags: JavaScript
Infelizmente, apesar do Arrow Function ser uma feature muito bacana e útil do ES6, saiba que nem sempre será possível utilizar ela, pois ela não foi feita para substituir 100% a declaração de function principal, o arrow function, apesar de trazer um syntax sugar e algumas utilidades como, por exemplo, compartilhamento de contextos, você precisa antes de usá-la, aprender também quando não usá-la para que você não fique perdido na procura de um bug de difícil de resolver, veja a seguir uma lista com possíveis situações para NÃO USAR arrow funcition.
Click handlers
Para exemplificar, vamos supor que existe um botão pelo qual queremos mudar sua cor entre azul e vermelho, conforme ele é clicado, para isso temos o seguinte html:
<style>
button { background-color: blue; }
.on { background-color: red; }
</style>
<button id="click_here">CLIQUE AQUI!</button>
Agora vamos programar o evento de click desse botão, usando arrow function:
const button = document.querySelector('#click_here');
button.addEventListener('click', () => {
this.classList.toggle('on');
});
Se você testar esse botão, vai gerar o erro: TypeError, cannot read property 'toggle' of undefined
Isso ocorre pois o this
de this.classList.toggle('on')
compartilha os atributos de window
e não do evento. E com isso nesse caso o ideal é utilizar a declaração de function:
const button = document.querySelector('#click_here');
button.addEventListener('click', function() {
this.classList.toggle('on');
});
Object methods
Se você pretende criar um object methods no frontend, não é recomendado utilizar arrow functions em seus métodos, entenda o porque vendo esse exemplo:
const Usuario = {
pontos: 20,
ganhou: () => {
this.pontos++;
}
}
Se você rodar Usuario.ganhou()
, algumas vezes, a expectativa é que os pontos
esteja com valores acima do que foi estabelecido em seu estado inicial, ou seja, maior que 20.
Mas se você acessar: Usuario.pontos
seu valor vai continuar 20, e isso ocorre pelo fato de que o this
, estará sendo referenciado ao objeto window
do browser, herdando seu escopo.
Para resolver esse problema, você pode tanto usar a declaração clássica de function
, quanto usar a declaração de métodos do Object methods:
// Declarando com function
const Usuario = {
pontos: 20,
ganhou: function() {
this.pontos++;
}
}
// Utilizando Object methods
const Usuario = {
pontos: 20,
ganhou() {
this.pontos++;
}
}
Argumentos de um objeto
Quando se cria uma função que trabalhe com arguments
, caso você precise tratar esses arguments em uma função interna, também não é recomendado usar arrow function, veja esse exemplo:
const ordernaPlayers = () => {
const players = Array.from(arguments);
return players.map((player, i) => {
return `${player} chegou em #${i + 1}`;
})
console.log(arguments);
}
O problema nesse exemplo é que a função ordernaPlayers()
vai gerar o erro: ReferenceError, arguments is not defined.
, esse erro ocorrerá pelo simples fato de que arguments
vai retornar um array e arrays não trabalham com a keyword this
, e mesmo não utilizando essa keyword, vai ocorrer esse erro, para resolver esse bug, basta aplicar function na função pai, a ordernaPlayers()
:
const ordernaPlayers = function() {
const players = Array.from(arguments);
return players.map((player, i) => {
return `${player} chegou em #${i + 1}`;
})
console.log(arguments);
}
Prototypes
Jamais use arrow function em funções prototype de um objeto, simplesmente os atributos não serão definidos mesmo instanciando o objeto corretamente, veja esse exemplo:
class Cliente {
constructor(nome, idade) {
this.nome = nome;
this.idade = idade;
}
}
Cliente.prototype.apresentar = () => {
return `Cliente: ${this.nome} | Idade: ${this.idade}`;
};
Agora tente instanciar um cliente e em seguida se você invocar a função Cliente.prototype.apresentar()
a interpolação de seus atributos no resultado final será simplesmente undefined
.
const john = new Cliente('John Connor', 25);
const mary = new Cliente('Mary Jane', 20);
john.apresentar(); // 'Cliente: undefined | Idade: undefined'
mary.apresentar(); // 'Cliente: undefined | Idade: undefined'
Simplesmente o arrow function para funções de um objeto prototype não mantém estado após instanciado. O ideal nesse caso é manter a declaração de function
normal:
Cliente.prototype.apresentar = function() {
return `Cliente: ${this.nome} | Idade: ${this.idade}`;
};
Recentemente lancei o ebook JavaScript Awesome Tips (Br version) com diversas dicas sobre JavaScript, vale a pena a leitura!