* Provavelmente, perdi alguma coisa, mas tenho certeza que os comentários vão me dizer issoEstou escrevendo este artigo para minhas necessidades pessoais. Está planejado que ele contenha as respostas para todas as perguntas que os alunos me fizerem sobre este tópico. Se é útil para outra pessoa - ótimo.
Conteúdo
- 1. Introdução
- Equívocos sobre isso
- Como determinar o valor deste
1. Introdução
A
this
-
this
é um dos recursos mais confusos da linguagem JavaScript. Vindo de Java, ele pretendia ajudar na implementação do OOP. Escrevi em Java por algum tempo e devo dizer que, durante esse período, talvez tenha duvidado do que é igual em um determinado local do código. No JavaScript, essas dúvidas podem surgir todos os dias - pelo menos até o momento em que você aprende algumas regras simples, mas não óbvias.
Equívocos sobre this
Existem vários conceitos errados comuns sobre essa palavra-chave. Quero dissipá-los rapidamente antes de chegar ao ponto.
este é um contexto lexical.Essa impressão geralmente surge entre iniciantes. Parece-lhes que
this
é um objeto no qual, como propriedades, todas as variáveis nesse escopo são armazenadas. Esse equívoco decorre do fato de que, em um caso particular, grosso modo, é assim. Se estivermos no nível mais alto,
this
igual à
window
(no caso de um script regular no navegador). E como sabemos, todas as variáveis declaradas no nível superior estão disponíveis como propriedades da
window
.
Em geral, isso não é verdade. Isso é fácil de verificar.
function test(){ const a = " , "; console.log(this.a); } test();
este é o objeto ao qual o método pertenceNovamente, isso é verdade em muitos casos específicos, mas nem sempre. O importante é como a função é chamada, e não se é uma propriedade de algum objeto. Isso é compreensível mesmo a partir de uma lógica muito simples: suponha que a mesma função seja uma propriedade de dois objetos simultaneamente.
const f = function(){ console.log(this); } const object1 = { method: f }; const object2 = { method: f };
Então, qual desses objetos será ela?
Importante! Mesmo que um objeto seja criado usando as classes ES6, isso não garante que seu método sempre o tenha. Não se deixe enganar pela semelhança com classes de idiomas "normais".
esta é uma técnica Jedi que, uma vez aprendida, precisa ser usada em qualquer lugarÉ melhor evitar usá-
this
se possível. O único caso em que é totalmente justificado é OOP. Em outros lugares, usar
this
não é apenas mau, mas geralmente é um exagero que confunde o código. Em essência,
this
é um argumento adicional, menos o primeiro, para a função, que é passada de maneira complicada e não óbvia para o iniciante. Com alta probabilidade, ele pode ser substituído pelo argumento usual e só ficará melhor.
Como determinar o valor deste
Aqui tentarei fornecer um algoritmo rigoroso e conciso com o qual até mesmo um codificador inexperiente será capaz de entender o que
this
é igual no seu caso particular. Explicações mais detalhadas serão escondidas sob os spoilers, para não bagunçar o espaço visual.
- Estamos dentro de uma função?
ComentárioNo código de nível superior (não dentro de nenhuma função), this
sempre se refere a um objeto global. No caso de um script regular no navegador, este é um objeto de window
. Mas, em geral, existem casos diferentes.
- Estamos dentro da função de seta?
- Sim: o valor
this
é o mesmo da função um nível mais alto (ou seja, contendo este). Volte à etapa anterior e repita o algoritmo para ela. Se a função não estiver contida em nenhuma outra, this
é um objeto global. - Não: veja o próximo parágrafo.
ComentárioUma das principais características das funções de seta é o chamado " this
lexical". Isso significa que o valor this
na função de seta é determinado apenas por onde (em que contexto lexical) ele foi criado e não depende de como foi chamado posteriormente. Às vezes, não é disso que precisamos, mas mais frequentemente torna as funções de seta muito convenientes e previsíveis.
- Essa função é chamada como construtor (usando o novo operador)?
- Sim: refere-se a um novo objeto que está "em construção".
- Não: veja o próximo parágrafo.
ComentárioTalvez valha a pena especificar o caso separadamente quando se trata do construtor da classe ES6 herdada. Então, antes de chamar super()
, this
não tem um valor (acessá-lo causará um erro) e, após chamar super()
será igual ao novo objeto da classe pai.
- Esta função é criada usando o bind ?
- Sim: o valor
this
é igual ao valor do primeiro argumento que passamos para o método bind
ao criar esta função. - Não: veja o próximo parágrafo.
ComentárioO método bind
cria uma cópia da função, corrigindo this
e, opcionalmente, os primeiros argumentos para ela. De fato, isso cria não apenas uma cópia da função, mas, cito, um "objeto BoundFunction exótico". Seu exotismo se manifesta, em particular, no fato de que, por um repetido chamado para bind
, não podemos mais mudar this
. Portanto, estritamente falando, a resposta neste parágrafo deve ser formulada da seguinte maneira: se assim for, então this
é igual ao primeiro argumento da primeira chamada para bind
, o que levou à criação dessa função.
- Essa função é passada em algum lugar como retorno de chamada ou manipulador?
- Sim: somente o Senhor sabe o que será igual quando convocado. Vá ler a documentação para o que causará isso.
- Não: veja o próximo parágrafo.
ComentárioPara uma função que não seja seta e vinculada, o valor
this
depende das circunstâncias em que foi chamada. Se você não chamar pessoalmente, mas passá-lo para algum lugar,
this
valor poderá ou não ser substituído por um valor desconhecido.
Exemplos:
`use strict` document.addEventListener('keydown', function(){ console.log(this); });
- Essa função é chamada usando o apply ou call ?
- Sim: neste caso,
this
é igual ao primeiro argumento passado para o método correspondente. - Não: veja o próximo parágrafo.
ComentárioOutra maneira de definir this
explicitamente. Mais precisamente, dois. No entanto, em termos this
há diferença entre apply
e call
, a única diferença é como o restante dos argumentos é passado.
- Essa função é obtida como o valor de uma propriedade do objeto e chamada imediatamente?
- Sim:
this
é igual ao objeto acima. - Não: veja o próximo parágrafo.
ComentárioNa verdade, a partir desse mecanismo (bem como da experiência de trabalhar com outras línguas), crescem as pernas da crença de que "
this
é o objeto cujo método chamamos". Talvez eu apenas escreva o código.
'use strict'; const object1 = { method: function(){ console.log(this); } } const object2 = { method: object1.method } object1.method();
- O código é executado no modo estrito? ('use strict', módulo ES6)
- Sim:
this
é igual a undefined
. - Não: é igual a um objeto global.
ComentárioSe chegarmos a esse ponto,
this
não
this
definido por nenhum dos mecanismos que permitem que ele seja definido. Existem vários conceitos errados sobre como isso pode ser passado. Por exemplo, durante as entrevistas, eles costumam me dizer uma coisa dessas:
const obj = { test: function(){ (function(){ console.log(this); })();
Ou, como eu disse na seção "equívocos", muitas pessoas pensam que, se uma função é um método de um objeto criado usando as classes ES6, isso sempre será igual a esse objeto. Isso também não é verdade.
Portanto, se chegarmos a esse ponto, as outras circunstâncias de chamar nossa função não importam. E tudo se resume a estar ou não no modo estrito.
Historicamente, como "padrão"
this
, um objeto global foi passado para essas funções. Essa abordagem foi posteriormente reconhecida como insegura. O ES5 introduziu um modo estrito que corrige muitos problemas das versões anteriores do ECMAScript. Ele está incluído na diretiva 'use strict' no início de um arquivo ou função. Nesse modo, o valor "padrão"
this
é
undefined
.
Nos módulos ES6, o modo estrito é ativado por padrão.
Também existem outros mecanismos para incluir o modo estrito, por exemplo, no NodeJS, o modo estrito para todos os arquivos pode ser ativado com o
--use-strict
.
Isso, em geral, é tudo. Determinar o valor
this
, é claro, é menos simples do que gostaríamos, mas também não é tão difícil quanto parece. Aprenda esse algoritmo como uma tabela de multiplicação - e você nunca mais terá problemas com
this
. Essas coisas.
O usuário PS
Aingis sugeriu que, ao usar a construção
with , o objeto passado como um contexto substitui o objeto global. Talvez eu não insira isso no meu classificador, porque a chance de encontrar em 2019+ é bastante pequena. Mas, de qualquer forma, esse é um ponto interessante.
O usuário do PPS
rqrqrqrq sugeriu que
new
prioridade mais alta que
bind
. A revisão correspondente ao classificador já foi feita. Obrigada