O que é isso? O que é isso? Tem algo muito errado

Cenário

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 thistrata 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 argumentsvariável. Uma grande diferença com a argumentsvariá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 thisaponta 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 windowobjeto 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 thisobjeto muda seu valor do objeto Global / Head? Aqui estão eles:

  • Sempre que uma função é chamada applyou callusada.
  • Sempre que uma função aninhada é chamada
  • Sempre que uma função é chamada com a newpalavra 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.namepumpkin.statuswindow

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 thismuda 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 thisdurante 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 calle apply? Aposto que eles fazem mais sentido agora com este exemplo!

getHoliday.call(halloweenTown, null)
getHoliday
.call(window, null)

Basicamente, estamos informando à função getHolidayqual valor thisdeve ter. Vamos passar para o próximo caso!

Sempre que uma função aninhada é chamada

Agora, há um caso especial em que thispode 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()thistownthiswhosTheKingtown

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 thisvalor. 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 newpalavra 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 newpalavra chave, você apenas configura em vez de uma instância da “classe” Monster com uma propriedade .window.phrasephrase

Quando uma função é chamada com a newpalavra chave, o valor de thisrefere-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 thisserá 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, thisprocurei primeiro no Monsterobjeto; quando não conseguiu encontrar a propriedade phrase, ele iniciou o processo de pesquisa do protótipo, onde encontrou a phrasepropriedade como parte do protótipo de objeto, o verdadeiro rei dos objetos!

Esperançosamente, isso ajudou os desenvolvedores a entender melhor a thispalavra. Nenhuma cidade de Natal ou Halloween foi danificada no processo de elaboração deste artigo.