JavaScript: A função da palavra chave “this” e os métodos call, apply e bind

Este post foi escrito como parte de uma série de estudos (resumos) que estou fazendo sobre JavaScript, por isso foi imensamente inspirado na documentação oficial, o que explica muitas similaridades entre os textos. Mas é possível também encontrar aqui alguns pequenos pontos que aprendi que não estão no texto original.
Texto original: https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Operators/this

Em JavaScript o this tem um comportamento um pouco diferente das outras linguagens. Seu valor na maioria dos casos depende muito de como uma função é chamada, podendo assim ter seu valor trocado (bem estranho isso), mas é assim mesmo que ele funciona, o que confere muitos poderes para quem está utilizando e com grandes poderes vem grandes bugs :)

Sintaxe:

Em Contexto Global

Em um contexto global a palavra chave this tem o mesmo valor do objeto global (window):

O exemplo acima nos mostra que this é igual a window no contexto global

Em Contexto de função

Dentro de uma função o valor do this depende de como ela é chamada. Vamos aos cenários possíveis.

Para funções declaradas no escopo global:

Neste cenário o valor de this é sempre igual a window:

Mas se utilizamos o modo estrito no contexto da função, o valor de this neste caso será undefined, isso acontece porque neste modo, precisamos explicitamente especificar “quem” chamou a função. Por ex:

Para funções arrow

Nas funções arrow o this é definido pelo contexto ao qual está inserido, mesmo se chamado utilizando os métodos call, apply ou bind.

Como visto no exemplo acima, não importa o que se faça, o valor de this será sempre “window” para este cenário, pois a arrow function foi definida no escopo global.

Se tivéssemos definido a arrow function dentro de uma outra função, como abaixo:

O valor de this neste caso será referenciado ao contexto da função Pessoa.
IMPORTANTE: Interessante também demonstrar que SEM a arrow function o valor de this seria diferente, por ex:

Isto acontece porque antes das arrow functions, toda nova função definia seu próprio valor de this (um novo objeto no caso de um construtor, undefined em chamadas de funções com strict mode, o objeto de contexto se a função é chamada como um “método de objeto”, etc.). Este comportamento é importuno com um estilo de programação orientado a objeto.

Explicação retirada de: https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Functions/Arrow_functions

Como método de um objeto

Para funções (métodos) de objetos, o valor do this faz referencia ao próprio objeto no qual se originou a chamada.

No exemplo acima o this faz referencia ao próprio objeto “obj”.

Interessante lembrar que independente de onde a função foi definida e que se ela for referenciada para dentro de um objeto, o resultado será o mesmo. por ex:

Como visto acima a função independent foi definida primariamente fora do objeto ”obj” e referenciada logo após para a propriedade “obj.f” e no final obtivemos o mesmo resultado.

É importante lembrar também que o this se refere sempre ao membro mais imediato, como no exemplo abaixo:

this neste caso se refere ao objeto “b”, por isso retornou 42.

Na cadeia de protótipos (prototype chain) do objeto

Neste caso, o this sempre assume o valor da “instância” que fez por sua vez referencia ao objeto original.

Como visto no exemplo acima “p” é uma instância de “o” e por isso this se refere a “p”  

Em construtores

Quando uma função é usada como um construtor por intermédio da palavra new, o this vai se referir ao novo objeto criado (nova instancia).

Métodos call, apply e bind

Toda função que possui a palavra this dentro de seu corpo, pode usar um dos três métodos.

O this nos manipuladores de eventos no DOM

Para funções utilizadas como manipuladores de eventos, o this se refere sempre ao objeto no qual registrou o evento.