A palavra-chave "This"

A palavra-chave this se refere ao valor do objeto vinculado à função no momento da chamada. Isso significa que o valor dela é diferente dependendo de se uma função é chamada como um método, como uma função independente 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, acesso às propriedades e aos métodos definidos ao lado dela no escopo. O trabalho com this é semelhante, de certa forma, ao trabalho com uma variável declarada com const. Como uma constante, this não pode ser removido e o valor não pode ser reatribuído, mas os métodos e as 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 se refere à propriedade globalThis, que é uma referência ao objeto global na maioria dos ambientes JavaScript. No contexto de um script executado em um navegador da Web, o objeto global é o window:

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

No 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 restrito, 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 é chamada de "vinculação padrão" devido a esse comportamento legado.

Vinculação implícita

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

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 que a contém sã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 para this. Isso pode parecer uma questão técnica no contexto dos exemplos anteriores, mas, para usos mais avançados de this, é uma distinção essencial a ser considerada.

Em geral, use this de maneiras que não esperem que o código ao redor tenha qualquer 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 lexicalmente fechado. Isso significa que this em uma função de seta se refere ao valor de this no contexto mais próximo da 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 mais amplo.

No exemplo abaixo, myEnclosingMethod cria uma função de seta no objeto que a contém quando ela é executada. A instância de this dentro da função de seta agora se refere ao valor de this dentro do ambiente englobante, 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 de 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 lida com a maioria dos casos de uso para trabalhar com this. No entanto, às vezes, você pode precisar que o valor de this represente um contexto de execução específico, em vez do contexto presumido. Um exemplo ilustrativo, embora um pouco desatualizado, é trabalhar 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 limitação específica de setTimeout tenha sido resolvida por outros recursos, problemas semelhantes de "perda" de this foram resolvidos criando uma referência explícita ao valor de this no escopo do contexto pretendido. Às vezes, você pode encontrar instâncias de this sendo atribuídas a uma variável usando identificadores como that, self ou _this em bases de código legado. 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 rígido:

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

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

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

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 de nenhuma forma, 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 um construtor usando 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 de manipuladores 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 gerenciador:

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 <button>:

> Button {}

Quando uma função de seta é usada como um callback de listener de eventos, o valor de this é fornecido novamente pelo contexto de execução mais próximo. No nível superior, isso significa que this dentro de uma função de callback do gerenciador de eventos é globalThis:

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

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

Como 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, o this faz referência ao 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

Para um script executado 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