A palavra-chave "This"

A palavra-chave this refere-se ao valor do objeto que está vinculado à função no momento da chamada, o que significa que o valor é diferente, dependendo de uma função ser chamada como método, como uma função autônoma ou como um construtor.

Quando uma função é chamada, ela cria uma instância da palavra-chave this em segundo plano como uma referência ao objeto que contém essa função, concedendo acesso às propriedades e aos métodos definidos com ela de dentro do escopo. Trabalhar com this é semelhante em algumas maneiras a trabalhar com uma variável declarada com const. Assim como uma constante, this não pode ser removido e seu valor não pode ser reatribuído, mas os métodos e propriedades do objeto que a palavra-chave this contém podem ser alterados.

Vinculação global

Fora de uma função ou do contexto de um objeto, this refere-se à propriedade globalThis, que é uma referência ao objeto global na maioria dos ambientes JavaScript. No contexto de um script em execução em um navegador da Web, o objeto global é o window:

this;
> Window {0: Window, window: Window, self: Window, document: document, name: '', location: Location, ...}

Em Node.js, globalThis é o objeto global:

$ node
Welcome to Node.js v20.10.0.
Type ".help" for more information.
> this
<ref *1> Object [global] {
...
}

Fora do modo estrito, this também se refere ao objeto global dentro de uma função independente, porque o Window pai é o objeto que "possui" essas funções.

function myFunction() {
    console.log( this );
}
myFunction();
> Window {...}

(function() {
    console.log( this );
}());
> Window {...}

Ao usar o modo estrito, this tem um valor de undefined dentro de uma função independente:

(function() {
    "use strict";
    console.log( this );
}());
> undefined

Antes da introdução do modo restrito, um valor null ou undefined para this seria substituído por uma referência ao objeto global. Às vezes, a vinculação global pode ser chamada de "vinculação padrão" devido a esse comportamento legado.

Vinculação implícita

Quando uma função é chamada como método de um objeto, uma instância de this dentro desse método se refere ao objeto que contém o método, concedendo acesso aos métodos e propriedades ao lado:

let myObject = {
    myValue: "This is my string.",
    myMethod() {
            console.log( this.myValue );
    }
};

myObject.myMethod();
> "This is my string."

Pode parecer que o valor de this depende de como uma função e o objeto dela estão definidos. Em vez disso, o contexto do valor de this é o contexto de execução atual. Nesse caso, o contexto de execução é que o objeto myObject está chamando o método myMethod. Portanto, myObject é o valor de this. Isso pode parecer técnico no contexto dos exemplos anteriores, mas, para usos mais avançados de this, é uma distinção essencial a ter em mente.

Em geral, use this de maneiras que não esperem que o código circundante tenha uma estrutura específica. A exceção a essa regra são as funções de seta do ES5.

this em funções de seta

Em funções de seta, this é resolvido como uma vinculação em um ambiente que abrange lexicamente. Isso significa que this em uma função de seta se refere ao valor de this no contexto de inclusão mais próximo dessa função:

let myObject = {
    myMethod() { console.log( this ); },
    myArrowFunction: () => console.log( this ),
    myEnclosingMethod: function () {
        this.myArrowFunction = () => { console.log(this) };
    }
};

myObject.myMethod();
> Object { myMethod: myMethod(), myArrowFunction: myArrowFunction() }

myObject.myArrowFunction();
> Window {...}

No exemplo anterior, myObject.myMethod() registra myObject como o objeto que "possui" esse método, mas myObject.myArrowFunction() retorna globalThis (ou undefined), porque a instância de this dentro da função de seta se refere ao escopo de inclusão mais alto.

No exemplo a seguir, myEnclosingMethod cria uma função de seta no objeto que a contém quando é executado. A instância de this dentro da função de seta agora se refere ao valor de this dentro do ambiente delimitado, que é o método que contém essa função de seta. Como o valor de this dentro de myEnclosingMethod se refere a myObject, depois que você definir a função de seta, this dentro da função de seta também se refere a myObject:

let myObject = {
    myMethod() { console.log( this ); },
    myEnclosingMethod: function () {
        this.myArrowFunction = () => { console.log(this) };
    }
};

myObject.myEnclosingMethod();
myObject.myArrowFunction();
> Object { myMethod: myMethod(), myArrowFunction: myArrowFunction() }

Vinculação explícita

A vinculação implícita processa a maioria dos casos de uso para trabalhar com this. No entanto, às vezes você pode precisar do valor de this para representar um contexto de execução específico, em vez do contexto presumido. Um exemplo ilustrativo, se ligeiramente desatualizado, está funcionando com this na função de callback de um setTimeout, porque esse callback tem um contexto de execução exclusivo:

var myObject = {
  myString: "This is my string.",
  myMethod() {
    console.log( this.myString );
  }
};
myObject.myMethod();
> "This is my string."

setTimeout( myObject.myMethod, 100 );
> undefined

Embora essa deficiência específica de setTimeout tenha sido resolvida por outros recursos, problemas semelhantes de "perda" de this foram resolvidos anteriormente com a criação de uma referência explícita ao valor de this no escopo do contexto pretendido. É possível que você veja instâncias de this sendo atribuídas a uma variável usando identificadores como that, self ou _this em bases de código legadas. Estas são convenções de identificador comuns para variáveis que contêm um valor this transmitido.

Quando você chama uma função usando os métodos call(), bind() ou apply(), this faz referência explícita ao objeto que está sendo chamado:

let myFunction = function() {
    console.log( this.myValue );
}

let myObject = {
   "myValue" : "This is my string."
 };

myFunction.call( myObject );
> "This is my string."
var myObject = {
  myString: "This is my string.",
  myMethod() {
    console.log( this.myString );
  }
};

setTimeout( myObject.myMethod.bind( myObject ), 100 );
> "This is my string."

A vinculação explícita substitui o valor this fornecido pela vinculação implícita.

let myObject = {
    "myValue" : "This string sits alongside myMethod.",
    myMethod() {
        console.log( this.myValue );
    }
};
let myOtherObject = {
    "myValue" : "This is a string in another object entirely.",
};

myObject.myMethod.call( myOtherObject );
> "This is a string in another object entirely."

Se uma função for chamada de uma maneira que defina o valor de this como undefined ou null, esse valor será substituído por globalThis fora do modo estrito:

let myFunction = function() {
    console.log( this );
}

myFunction.call( null );
> Window {...}

Da mesma forma, se uma função for chamada de uma maneira que forneça a this um valor primário, esse valor será substituído pelo objeto wrapper do valor primitivo fora do modo restrito:

let myFunction = function() {
    console.log( this );
}

let myNumber = 10;

myFunction.call( myNumber );
> Number { 10 }

No modo estrito, um valor this transmitido não é convertido em um objeto, mesmo que seja um valor primitivo, null ou undefined:

"use strict";
let myFunction = function() {
    console.log( this );
}

let myNumber = 10;

myFunction.call( myNumber );
> 10

myFunction.call( null );
> null

Vinculação de new

Quando uma classe é usada como construtor com a palavra-chave new, this se refere à instância recém-criada:

class MyClass {
    myString;
    constructor() {
        this.myString = "My string.";
    }
    logThis() {
        console.log( this );
    }
}
const thisClass = new MyClass();

thisClass.logThis();
> Object { myString: "My string." }

Da mesma forma, o valor de this dentro de uma função de construtor chamada usando new se refere ao objeto que está sendo criado:

function MyFunction() {
  this.myString = "My string.";
  this.logThis = function() {
    console.log( this );
  }
}
const myObject = new MyFunction();

myObject.logThis();
> Object { myString: "My string.", logThis: logThis() }

Vinculação do manipulador de eventos

No contexto de manipuladores de eventos, o valor de this faz referência ao objeto que o invoca. Dentro da função de callback de um manipulador de eventos, isso significa que this faz referência ao elemento associado ao manipulador:

let button = document.querySelector( "button" );

button.addEventListener( "click", function( event ) { console.log( this ); } );

Quando um usuário interage com o button no snippet anterior, o resultado é o objeto de elemento que contém o próprio <button>:

> Button {}

Quando uma arrow function é usada como um callback de listener de eventos, o valor de this é novamente fornecido pelo contexto de execução delimitado mais próximo. No nível superior, isso significa que o this dentro de uma função de callback do manipulador de eventos é globalThis (ou undefined, no modo estrito):

let button = document.querySelector( "button" );

button.addEventListener( "click", ( event ) => { console.log( this ); } );
> undefined

Como acontece com qualquer outro objeto, quando você usa os métodos call(), bind() ou apply() para referenciar a função de callback de um listener de eventos, this referencia o objeto explicitamente:

let button = document.querySelector( "button" );
let myObject = {
    "myValue" : true
};
function handleClick() {
    console.log( this );
}

button.addEventListener( "click", handleClick.bind( myObject ) );
> Object { myValue: true }

Teste seu conhecimento

No caso de um script em execução em um navegador da Web, qual é o objeto global a que this se refere quando usado fora de uma função ou do contexto de um objeto?

O objeto window
O objeto browser
O objeto undefined