JavaScript é uma linguagem de paradigmas múltiplos que suporta programação orientada a objetos e ligação dinâmica de métodos - um conceito poderoso que permite que a estrutura do código JavaScript seja alterada durante a execução do programa. Isso oferece aos desenvolvedores sérias oportunidades, torna o idioma flexível, mas você precisa pagar por tudo. Nesse caso, você deve pagar com a compreensibilidade do código. Uma contribuição significativa para esse preço é feita pela
this
, em torno do comportamento do qual muitas coisas foram coletadas que podem confundir o programador.

Vinculação de método dinâmico
A ligação dinâmica permite especificar, durante a execução do programa, e não durante a compilação, o método que deve ser chamado ao executar um determinado comando. Em JavaScript, esse mecanismo é implementado usando a
this
e a cadeia de protótipos. Em particular, o valor específico
this
dentro do método é determinado em tempo de execução, e as regras para determinar esse valor variam dependendo de como o método foi declarado.
Vamos jogar um jogo. Eu chamo de "O que está escrito nisso?". Aqui está sua primeira opção - código do módulo ES6:
const a = { a: 'a' }; const obj = { getThis: () => this, getThis2 () { return this; } }; obj.getThis3 = obj.getThis.bind(obj); obj.getThis4 = obj.getThis2.bind(obj); const answers = [ obj.getThis(), obj.getThis.call(a), obj.getThis2(), obj.getThis2.call(a), obj.getThis3(), obj.getThis3.call(a), obj.getThis4(), obj.getThis4.call(a) ];
Antes de ler mais, pense sobre o que cairá na matriz de respostas e anote as respostas. Depois de fazer isso, teste-se
answers
matriz de
answers
usando
console.log()
. Você conseguiu descriptografar corretamente o valor
this
em cada um dos casos?
Vamos analisar esse problema, começando com o primeiro exemplo. A construção
obj.getThis()
retorna
undefined
. Porque Esta função de seta não pode ser vinculada. Tais funções usam
this
de seu escopo lexical circundante. O método é chamado no módulo ES6; em seu escopo lexical,
this
será
undefined
. Pelo mesmo motivo,
undefined
retornará uma chamada para
obj.getThis.call(a)
. O valor
this
ao trabalhar com funções de seta não pode ser reatribuído mesmo com
.call()
ou
.bind()
. Esse valor sempre corresponderá a
this
do escopo lexical, no qual essas funções estão localizadas.
O comando
obj.getThis2()
demonstra como trabalhar com
this
ao usar métodos de objeto regulares. Se
this
não
this
vinculado a um método semelhante e desde que esse método não seja uma função de seta, ou seja, ele suporte
this
ligação, a palavra-chave
this
será vinculada ao objeto para o qual o método é chamado usando a sintaxe de acesso às propriedades do objeto por meio de ponto ou usando colchetes.
A construção
obj.getThis2.call(a)
já é um pouco mais difícil de descobrir. O método
call()
permite chamar uma função com um determinado valor
this
, que é indicado como um argumento opcional. Em outras palavras, nesse caso,
this
é obtido do parâmetro
.call()
; como resultado, a chamada para
obj.getThis2.call(a)
retorna o objeto
a
.
Usando o comando
obj.getThis3 = obj.getThis.bind(obj);
estamos tentando vincular a
this
método, que é uma função de seta. Como já descobrimos, isso não pode ser feito. Como resultado, as chamadas para
obj.getThis3()
e
obj.getThis3.call(a)
retornam
undefined
.
Métodos que são funções comuns podem ser anexados a
this
, então
obj.getThis4()
, como esperado, retorna
obj
. Uma chamada para
obj.getThis4.call(a)
retorna
obj
, e não, como
obj.getThis4.call(a)
esperar,
a
. O fato é que, antes de chamar esse comando, já o vinculamos ao
obj.getThis4 = obj.getThis2.bind(obj);
. Como resultado, ao executar
obj.getThis4.call(a)
, o estado do método em que estava após a primeira ligação ter sido levada em consideração é levado em consideração.
Usando isso nas classes
Aqui está a segunda versão do nosso jogo - a mesma tarefa, mas agora baseada em classes. Aqui, usamos a sintaxe para declarar campos de classe pública (no momento, a
proposta para essa sintaxe está no terceiro estágio de aprovação, ela está disponível por padrão no Chrome, você pode usá-la com
@babel/plugin-proposal-class-properties
).
class Obj { getThis = () => this getThis2 () { return this; } } const obj2 = new Obj(); obj2.getThis3 = obj2.getThis.bind(obj2); obj2.getThis4 = obj2.getThis2.bind(obj2); const answers2 = [ obj2.getThis(), obj2.getThis.call(a), obj2.getThis2(), obj2.getThis2.call(a), obj2.getThis3(), obj2.getThis3.call(a), obj2.getThis4(), obj2.getThis4.call(a) ];
Antes de continuar lendo, pense no código e escreva sua visão do que será inserido no array
answers2
.
Você terminou?
Aqui, todas as chamadas de método, exceto
obj2.getThis2.call(a)
, retornarão uma referência à instância do objeto. A mesma chamada retornará o objeto
a
. As funções de seta ainda levam
this
do escopo lexical. A diferença entre este exemplo e o anterior é a diferença no escopo do qual
this
é tirado.
Ou seja, aqui trabalhamos com propriedades de classe, que determinam o comportamento desse código.
O fato é que, durante a preparação do código para execução, os valores são gravados nas propriedades das classes assim:
class Obj { constructor() { this.getThis = () => this; } ...
Em outras palavras, verifica-se que a função de seta é declarada dentro do contexto da função de construtor. Como estamos trabalhando com uma classe, a única maneira de instanciar é usar a
new
palavra-chave (se você esquecer essa palavra-chave, uma mensagem de erro será exibida).
As tarefas mais importantes resolvidas pela
new
palavra-chave são criar uma nova instância do objeto e vinculá-
this
ao construtor. Esse recurso, levando em conta o que já falamos na seção anterior, deve ajudá-lo a entender o que está acontecendo.
Sumário
Você concluiu as tarefas descritas neste artigo? Um bom entendimento de como
this
palavra
this
chave se comporta no JavaScript economizará muito tempo durante a depuração, ao procurar razões não óbvias para erros obscuros. Se você respondeu algumas das perguntas incorretamente, significa que será útil para você praticar.
Experimente o código de exemplo e tente novamente, e assim por diante, até poder responder a todas as perguntas corretamente. Depois de descobrir você mesmo, encontre alguém pronto para ouvi-lo e diga a ele por que os métodos das tarefas retornam exatamente o que eles retornam.
Se tudo isso lhe parece mais complicado do que o esperado, saiba que você não está sozinho nisso. Testei alguns desenvolvedores para conhecer os recursos
this
e acho que apenas um deles foi absolutamente preciso em todas as suas respostas.
Esse subsistema da linguagem, que no início parecia uma pesquisa dinâmica de métodos que podiam ser influenciados usando
.call()
,
.bind()
ou
.apply()
, começou a parecer muito mais complicado após o aparecimento das funções e classes das setas.
Aparentemente, será útil observar os principais recursos de classes e funções de seta em termos de uso
this
. Lembre-se de que as funções de seta sempre usam
this
de seu escopo lexical, e a
this
nas classes está, de fato, vinculada à função construtora da classe. E se você sentir que não sabe exatamente o que
this
aponta, use o depurador para verificar suas suposições sobre isso.
Além disso, lembre-se de que você pode fazer muito em JavaScript sem usá-
this
em seu código. A experiência me diz que quase qualquer código JS pode ser reescrito na forma de funções puras que aceitam todos os argumentos com os quais trabalham, na forma de uma lista explicitamente especificada de parâmetros (
this
pode ser interpretado como um parâmetro implicitamente especificado com um estado mutável). A lógica contida nas funções puras é determinística, o que melhora sua testabilidade. Tais funções não têm efeitos colaterais, o que significa que, ao trabalhar com elas, ao contrário de manipular
this
, é improvável que você “quebre” qualquer coisa fora dela. Sempre que você altera
this
, você se depara com um problema em potencial, que é o de que algo que depende
this
pode parar de funcionar corretamente.
Apesar do exposto, note-se que
this
é um conceito útil. Por exemplo, ele pode ser aplicado para organizar o compartilhamento de um determinado método por uma infinidade de objetos. Mesmo na programação funcional,
this
pode ser útil para chamar outros métodos a partir de um método de um objeto, o que permite criar algo novo com base nas construções existentes.

