JavaScript Function bind()
Aprenda vinculação de funções em JavaScript: por que métodos perdem o `this` ao serem passados como callbacks ou ao setTimeout, como func.bind() resolve isso, aplicação parcial com bind e bind vs arrow functions.
Em JavaScript, o valor de this dentro de um método é definido quando a função é chamada, não quando é escrita. No momento em que você desvincula um método do seu object — passando-o como callback ou para setTimeout — ele esquece a qual object pertencia. A vinculação de função é a solução: ela trava permanentemente o this a um object escolhido para que o método se comporte da mesma forma independentemente de onde é chamado.
Este capítulo aborda quando e por que o this é perdido, como func.bind() resolve isso, como usar bind para aplicação parcial e como bind se compara às arrow functions.
O problema de "perder o this"
Um método funciona bem quando chamado como object.method(), pois this é definido como o que está à esquerda do ponto. Mas passe esse mesmo método para outro lugar e o ponto desaparece — então o this é perdido.
A segunda chamada imprime Hello, undefined! porque runLater invocou callback() como uma função simples, então this não é mais user. (No modo estrito, this é undefined e acessar this.firstName lançaria um TypeError.)
O mesmo acontece com setTimeout — ele armazena a função e depois a chama por conta própria, sem nenhum object vinculado:
Para saber mais sobre como o this é resolvido dentro de métodos, consulte Métodos de object, "this".
Resolvendo com func.bind()
O método func.bind(thisArg) retorna uma nova função cujo this é permanentemente definido como thisArg. A função original não é alterada — você obtém uma cópia vinculada.
Um padrão comum é armazenar a versão vinculada de volta no object para que toda referência seja segura de ser passada adiante:
A vinculação acontece apenas uma vez
Uma vez que uma função está vinculada, o this fica fixo para sempre. Chamar bind novamente no resultado não tem efeito — a segunda vinculação é ignorada.
Aplicação parcial: pré-definindo argumentos
O bind aceita argumentos após thisArg, e eles são passados para a função original antes de quaisquer argumentos posteriores. Isso permite criar uma função especializada a partir de uma mais geral — chamada de aplicação parcial.
Você também pode pré-definir this e argumentos juntos:
bind vs. arrow functions
Uma arrow function não possui seu próprio this — ela herda o this do escopo ao redor no momento em que é escrita (this léxico). Isso torna as arrows uma alternativa leve ao bind quando você precisa manter o this externo dentro de um callback:
Como escolher:
- Use uma arrow function para capturar o
thisatual de forma inline, especialmente em callbacks onde você não precisa de uma função reutilizável separadamente. - Use
bindquando precisar de uma função independente com umthisfixo para passar a outro lugar, ou quando também quiser pré-definir argumentos. Ao contrário de uma arrow, uma função vinculada pode ser armazenada, reutilizada e passada por nome.
Uma ressalva: uma arrow function não pode ser usada como um método de object que depende do this apontando para o object, pois ela captura o this do escopo ao redor (muitas vezes o object global) em vez do chamador.
Quando usar isso?
- Passando um método para um manipulador de eventos,
setTimeout/setInterval,Promise.thenou métodos de array comoforEach. - Construindo funções especializadas a partir de gerais com aplicação parcial (por ex.,
bind(null, presetArg)). - Sempre que um método deve continuar funcionando após ser desvinculado do seu object.
Se você precisar chamar uma função com um this escolhido imediatamente (em vez de criar uma cópia reutilizável), use call/apply em vez disso — veja Decorators e encaminhamento, call/apply. Para uma visão mais aprofundada do this em arrow functions, veja Arrow functions revisitadas.