this
é provavelmente um dos conceitos mais difíceis de entender em Javascript. Não porque seja complicado, mas porque é uma das coisas da linguagem Javascript que os desenvolvedores precisam memorizar para entender como funciona em cenários específicos. Vou tentar explicar do que se this
trata e sim, vão haver muitos trocadilhos.
O que é isso? O que é isso?
Primeiro, this
é um ponteiro , uma referência a um objeto. É criado sempre que uma função é criada e vive dentro de seu escopo da mesma forma que a arguments
variável. Uma grande diferença com a arguments
variável é que você não pode modificar seu valor .
function() { arguments = [] } // no error
function() { this = {} } // throws ReferenceError: Invalid left-hand side in assignment
O objeto this
aponta para refere-se ao objeto do qual essa função é uma propriedade / método . No Desenvolvimento Web, na maioria das vezes estamos chamando funções através do Global / Head, o window
objeto dentro do nosso Browser, onde todos os nossos objetos Javascript estão sendo armazenados. Em seu console favorito, se você digitar this
, obterá o objeto Global / Head mencionado anteriormente.
`this` // returns Window
Então, em quais cenários o this
objeto muda seu valor do objeto Global / Head? Aqui estão eles:
- Sempre que uma função é chamada
apply
oucall
usada. - Sempre que uma função aninhada é chamada
- Sempre que uma função é chamada com a
new
palavra – chave
Sempre que uma função é chamada, aplicar ou chamar são usados.
Vamos começar com o seguinte objeto
var pumpkin = {
name: "Jack",
status: "King",
whoGrewSoTired: function() { return "I, " + pumpkin.name + "! The pumpkin " + pumpkin.status}
}
Se você criar isso em seu console, verá que, ao chamar, será exibida uma mensagem adequada (ou lamentação, se desejar). Isso ocorre porque as variáveis e são realmente navegáveis a partir do objeto Head / Global . Isso seria o mesmo que escreverpumpkin.whoGrewSoTired()
pumpkin.name
pumpkin.status
window
var pumpkin = {
name: "Jack",
status: "King",
whoGrewSoTired: function() { return "I, " + window.pumpkin.name + "! The pumpkin " + window.pumpkin.status}
}
Agora, você provavelmente nunca viu isso antes (se viu, por favor, envie-me o e-mail do desenvolvedor, vou apresentá-lo a um amigo do Oogie Boogie que eu tenho). A razão é porque a maioria dos desenvolvedores em seu bom senso está ciente da Programação Orientada a Objetos (OOP) e o que eles querem é chamar as propriedades reais do objeto. E this
, meus amigos, this
é para isso.
var pumpkin = {
name: "Jack",
status: "King",
whoGrewSoTired: function() { return "I, " + this.name + "! The pumpkin " + this.status}
}
Então, como this
muda quando chamamos uma função? No código anterior, não tivemos problema em ver que recuperamos o nome e o status do objeto pumpkin
. Agora veja o seguinte código:
var season = "Christmas"
var halloweenTown = { season: "Halloween" }
var getHoliday = function() { return this.season }
halloweenTown.getHoliday = getHoliday;
halloweenTown.getHoliday() // returns "Halloween"
getHoliday() // returns "Christmas"
Por que estamos recuperando o valor “Halloween” para a cidade? Bem, porque o valor de this
durante a execução dessa função é a cidade-objeto, enquanto no último é a janela do objeto. Como estamos armazenando todas as nossas variáveis no objeto Head / Global, isso seria o mesmo de antes:
window.halloweenTown.getHoliday()
window.getHoliday()
Agora, você se lembra daqueles métodos Object call
e apply
? Aposto que eles fazem mais sentido agora com este exemplo!
getHoliday.call(halloweenTown, null)
getHoliday.call(window, null)
Basicamente, estamos informando à função getHoliday
qual valor this
deve ter. Vamos passar para o próximo caso!
Sempre que uma função aninhada é chamada
Agora, há um caso especial em que this
pode ficar um pouco confuso: funções aninhadas. Veja o seguinte código.
var town = {
name: "Christmas Town",
king: "Santa",
whosTheKing: function() {
var town = this.name;
var getKing = function() {
return this.king
}();
return getKing + " is the king of "+ town
}
}
Corra e uau, você obtém ‘undefined is the king of Christmas Town’. O que é isso? O que aconteceu com o Papai Noel? Ele foi sequestrado? Provavelmente, mas o verdadeiro problema é que o segundo não estava mais se referindo ao objeto! Você pode dizer “Bem, isso é óbvio, porque está sendo chamado pela função, e não ao contrário do primeiro!”. Então, você ficaria feliz se eu fizesse isso?town.whosTheKing()
this
town
this
whosTheKing
town
var town = {
name: "Christmas Town",
king: "Santa",
whosTheKing: function() {
var town = this.name;
var king = this.king;
var getKing = function() {
return this.king
}();
return getKing + " is the king of "+ town
}
}
Executá-lo. “undefined é o rei da cidade natal”. Se você está chocado this
, continue lendo!
(Na verdade, fiz algo de propósito para evitar esse erro. Para encontrá-lo, você só precisa ler esta resposta em StackOverflow que explica a diferença entre usar var e não usá-lo)
Ok, então o que está acontecendo? Aqui está a resposta: no ECMAScript 262 Ed.3, as funções aninhadas “perdem” a referência ao this
valor. Sempre que o “perdem”, eles se referem ao objeto Cabeça / Global. Portanto, a segunda função está realmente procurando a saída da variável. Posso provar aqui:window.king
window.king = "Jack"
town.whosTheKing(); // "Jack is the king of Christmas Town"
A boa notícia é que no ECMAScript 262 Ed. 5 isso está sendo resolvido. Nesse ínterim, uma solução alternativa que você provavelmente viu em algum código é a seguinte.
var town = {
name: "Christmas Town",
king: "Santa",
whosTheKing: function() {
var town = this.name;
that = this;
var getKing = function() {
return that.king
}();
return getKing + " is the king of "+ town
}
}
town.whosTheKing(); // "Santa is the king of Christmas Town"
Para não perder a referência, usamos uma variável auxiliar que armazena o ponteiro correto para nossa variável. Outra solução alternativa é usar um Closure que armazena a variável com o escopo adequado. Isso, no entanto, pode ficar confuso muito rápido.
var town = {
name: "Christmas Town",
king: "Santa",
whosTheKing: function() {
var town = this.name;
king = this.king;
var getKing = function() {
return this.king
}();
return getKing + " is the king of "+ town
}
}
town.whosTheKing(); // "Santa is the king of Christmas Town"
(Se você não entende isso, sugiro que leia a nota que coloquei anteriormente sobre a resposta StackOverflow)
Sempre que uma função é chamada com a nova palavra-chave
Ok, então já passamos quase todos os comportamentos de this
; o que falta é quando a new
palavra chega à cidade (entendeu? à cidade! Ah, tudo bem, vou parar). Deixe-me perguntar, qual você acha que será o valor ?boogieMan.phrase
var Monster = function(phrase) {
this.phrase = phrase;
}
var boogieMan = Monster("YOU'RE JOKIN', YOU'RE JOKIN', I CAN'T BELEVE MA EYEZ!");
boogieMan.phrase // returns ??
Ele retornará um erro. Por quê? Porque apesar do nosso design OOP à prova de balas, estamos apenas chamando uma função que retorna undefined
(todas as funções retornam um valor, mesmo que seja undefined
). Sem a new
palavra – chave, você apenas configura em vez de uma instância da “classe” Monster com uma propriedade .window.phrase
phrase
Quando uma função é chamada com a new
palavra – chave, o valor de this
refere-se ao próprio objeto, que é o design OOP adequado. Do nosso código anterior:
var Monster = function(phrase) {
this.phrase = phrase;
}
var boogieMan = new Monster("YOU'RE JOKIN', YOU'RE JOKIN', I CAN'T BELEVE MA EYEZ!");
boogieMan.phrase // returns "YOU'RE JOKIN', YOU'RE JOKIN', I CAN'T BELEVE MA EYEZ!"
E se o objeto não tiver a propriedade que procuramos? Javascript começará a procurar na cadeia de protótipos o valor correto e, portanto, o valor de this
será atualizado de acordo.
var Monster = function(phrase) {
if(phrase) this.phrase = phrase;
}
Object.prototype.phrase = "Eureka! This year, Christmas will be OURS";
var pumpkinKing = new Monster(); // We don't set the the property 'phrase'
pumpkinKing.phrase // returns "Eureka! This year, Christmas will be OURS"
No código anterior, this
procurei primeiro no Monster
objeto; quando não conseguiu encontrar a propriedade phrase
, ele iniciou o processo de pesquisa do protótipo, onde encontrou a phrase
propriedade como parte do protótipo de objeto, o verdadeiro rei dos objetos!
Esperançosamente, isso ajudou os desenvolvedores a entender melhor a this
palavra. Nenhuma cidade de Natal ou Halloween foi danificada no processo de elaboração deste artigo.