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:
1 |
this |
Em Contexto Global
Em um contexto global a palavra chave this tem o mesmo valor do objeto global (window):
1 2 3 4 5 |
// Em navegadores web, o objeto window é também o objeto global: console.log(this === window); // true this.a = 37; console.log(window.a); // 37 |
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:
1 2 3 4 5 |
function f1(){ return this; } f1() === window; // true |
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:
1 2 3 4 5 6 7 8 9 10 |
function f2(){ "use strict"; // assume modo estrito return this; } f2() === undefined; // true. Neste caso não especificamos quem é o responsável pela chamada da função window.f2() === window; // true. Aqui especificamos que "window" foi o responsável. var a = {"name": "Policarpo"}; f2.apply(a); // {"name": "Policarpo"}; Aqui mudamos o contexto para o objeto "a". |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
var func = (() => this); // esta função SEMPRE vai retorna window, // porque está no contexto global. console.log(func() === window); // true // Mesmo se utilizado o call, apply ou bind: // Chamando como um método de um objeto var obj = {func: func}; console.log(obj.func() === window); // true // Tentativa de definir this usando call console.log(func.call(obj) === window); // true // Tentantiva de definir this usando bind func = func.bind(obj); console.log(func() === window); // true |
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:
1 2 3 4 5 6 7 8 9 10 11 |
function Pessoa(){ this.idade = 0; var somar = () => { this.idade++; // |this| corretamente referência ao objeto Pessoa } somar(); somar(); } var p = new Pessoa(); console.log(p.idade); // 2 |
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:
1 2 3 4 5 6 7 8 9 10 11 |
function Pessoa(){ this.idade = 0; function somar() { this.idade++; // |this| NÃO se refere ao objeto Pessoa } somar(); somar(); } var p = new Pessoa(); console.log(p.idade); // 0 |
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.
1 2 3 4 5 6 7 8 |
var obj = { prop: 37, f: function() { return this.prop; } }; console.log(obj.f()); // 37 |
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:
1 2 3 4 5 6 7 8 9 |
var obj = {prop: 37}; function independent() { return this.prop; } obj.f = independent; console.log(obj.f()); // 37 também |
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:
1 2 |
obj.b = {g: independent, prop: 42}; console.log(obj.b.g()); // 42 |
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.
1 2 3 4 5 6 |
var o = {f:function(){ return this.a + this.b; }}; var p = Object.create(o); p.a = 1; p.b = 4; console.log(p.f()); // 5 |
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).
1 2 3 4 5 6 |
function Movie(){ this.name = "The Good, the Bad and the Ugly"; } var obj = new Movie(); console.log(obj.name); // logs "The Good, the Bad and the Ugly" |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
function add(c, d){ return this.a + this.b + c + d; } var o = {a:1, b:3}; // O primeiro parâmetro é o objeto a usar como // 'this'; subsequentes parâmetros são passados como // argumentos na função chamada. // Sempre é executada a função após a chamada. add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16 // O primeiro parâmetro é o objeto a usar como // 'this', o segundo é um (array) cujos // membros são usados como argumentos na função chamada. // Sempre é executada a função após a chamada. add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34 // Com o bind uma nova função é retornada com o contexto // apontando para o primeiro parâmetro do bind. // Não executa a função, apenas retorna uma nova. var new_add = add.bind({a:2, b:4}); new_add(10, 10) // 2 + 4 + 10 + 10 = 26 |
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.
1 2 3 4 5 |
function handler(e){ console.log(this); // <div id="my_ele"></div> } document.getElementById("my_ele").addEventListener('click', handler, false); |