Vou tentar fazer uma rápida porém merecida explicação sobre o uso do this
na execução de funções, tópico que tira a paciência de muita gente que tá começando na linguagem ou vem ~viciado de libs e frameworks.
Os exemplos aqui são executados no browser, mas podem ser executados no Node sem problema algum, mudando só o objeto window
para global
.
O que é isto?
Bom, você deve tentar adivinhar pela tradução que this
se refere a "isto". Não está totalmente errado, o ponto chave é o que é o "isto". Tente executar o this
no console, só ele e nada mais, e você vai receber o objeto window
. Esses são os objetos que, nos seus ambientes, guardam as referências pros outros objetos, funções, classes, etc, definidos pelo desenvolvedor. Ou seja, quando você define e atribui var a = 7
fora de escopo de funções ou fora de objetos, na verdade é criada uma referência para essa variável em window
, significando que dá pra acessar essa mesma variável tanto fazendo a
como window.a
.
Ok, mas e se eu definir uma função assim
function outerScope() {
console.log(this)
};
quando eu chamá-la eu vou rebecer a própria função? (??) Não.
Quando você chama outerScope()
na verdade é a mesma coisa de estar chamando window.outerScope()
e o this
vai mostrar window
. O que acontece é que o this
se refere justamente ao contexto de invocação, ou seja, como e onde ela é chamada. No exemplo, quem está chamando a função outerScope
implicitamente é o objeto window
.
this
em métodos
Ainda no mesmo ambiente, suponha que você agora defina um objeto o
assim:
var o = {
m: outerScope
};
A chave m
tem como valor a função definida anteriormente, o que faz com que m
seja um método do objeto o
. Pra executar, basta o.m()
.
TCHARAN! O que foi mostrado foi o próprio objeto o
, porque agora ele é quem executa essa função que agora foi atribuída a ele.
Percebe como nesse caso, mesmo a função sendo definida fora do objeto, quando é atribuída e trazida pra dentro do objeto,e a partir daí não tem mais relação com o que acontece externamente com a função, o this
muda? ;)
O mesmo comportamento acontece se tratando de eventos:
var el = document.querySelector('#submit-form');
el.addEventListener(
'click',
function() { console.log(this); }
)
No código acima, atribuímos um elemento HTML à variável el
, e depois definimos que o evento de click executa uma função que loga o this
. Nesse caso, também o this
se refere ao próprio elemento que disparou o evento, no caso el
.
Até agora imagino que tá tudo de boa, eu acho.
function
s criam escopo, e não preservam o this
do contexto
Voltemos ao exemplo do objeto, mas vamos criar mais um método:
var o = {
m: outerScope,
n: function() {
console.log(this);
function inside() {
console.log(this);
};
inside();
}
};
Aqui, adicionamos mais um método à o
, n
, que loga o this
duas vezes: uma diretamente no método e outra dentro de uma função que está dentro desse método. Se você executar o.n()
, sua reação pode ser das mais variadas: "whatta fuck" "Q" "BÉ ISSO, MAH" e por aí vai.
O primeiro this
se refere ao objeto o
, como anteriormente, porém sendo chamado dentro da função inside
ele mostra window
! Isso acontece porque, ao criar uma nova função com function
, o this
(e até arguments
) não é trazido do contexto da função mais externa para o função interna, e então ele se refere ao próprio window
.
Mas então, como diabos eu acessaria o this
da função externa? Quando eu tiver definindo uma função construtora e seus metódos, como é que eu ia referenciar o this
, que é o objeto criado?
1/2: arrow function
Se você é descolado(a) e quer usar as novas features da linguagem e dizer que tá por dentro, pode usar as queridinhas arrow functions. Mais do que uma forma curta de escrever funções anônimas (() => console.log(this)
), as arrow functions fazem o contexto permanecer o mesmo para o this
, ficando o código assim
var o = {
m: outerScope,
n: function() {
console.log(this);
// Tenho que autoexecutá-la já que é uma função anônima
(() => {
console.log(this);
})();
}
};
e mostrando duas vezes o objeto o
. Simples e elegante.
2/2: "that" pra quem te quer
Se você não quer usar arrow function, ou melhor, quando NÃO HAVIA ISSO NA LINGUAGEM, o que era feito era atribuir o valor de this
a outra variável no escopo acima, geralmente com o nome "that" ou "self" e aí sim através dela estaria disponível no escopo mais interno. Ficaria assim:
var o = {
m: outerScope,
n: function() {
console.log(this);
// TAH-DAH ;)
var that = this;
function inside() {
console.log(that);
};
inside();
}
};
Conclusão
Acho que consegui cobrir os principais casos do this
na invocação de funções. Se faltou alguma coisa (e faltou), comenta aí embaixo pra gente trocar uma ideia sobre :D
Pra um texto bem mais aprofundado e completo, recomendo demais a leitura do EXCELENTE You Don't Know JS: this & Object Prototypes, especialmente os capitulos 1 e 2 tratam desse tema.
Durante muito tempo eu só usei jQuery nas minhas páginas, pelos motivos óbvios: mais rapidez no desenvolvimento, segurança ao fazer uma página que vai funcionar na maior quantidade de navegadores possível, biblioteca que faz de tudo um pouco, etc. E longe de mim condenar a lib, eu acho que o que merece atenção é a atitude dos desenvolvedores que a utilizam sem conhecer a linguagem em si, porque você acaba ficando viciado nela sem realmente entender como a liguagem funciona e não sabe o que fazer quando você não tem ela à mão. Recomendo botar a mão na massa.
Ir para o topo