Palavra-chave this - JavaScript
O comportamento da palavra-chave this
Contexto Global e objeto globalThis
No contexto global, this
this
window
this
self
Por exemplo, no navegador, ao executar o seguinte código:
console.log(this);
Você verá algo semelhante a:
Window {window: Window, self: Window, document: document, name: "", location: Location, …}
O padrão ES2020 introduziu o objeto globalThis
console.log(globalThis);
Contexto de Função
Dentro de uma função, this
globalThis
function foo() {
var bar = "local";
console.log(this.bar);
}
var bar = "global";
foo(); // global
Se não usássemos this
function foo() {
var bar = "local";
console.log(bar);
}
var bar = "global";
foo(); // local
No entanto, se estivermos no modo estrito, this seria undefined
"use strict";
function foo() {
var bar = "local";
console.log(this.bar);
}
var bar = "global";
foo(); // erro: this = undefined
Contexto de Objeto
No contexto de um objeto, incluindo seus métodos, a palavra-chave this refere-se ao próprio objeto:
const obj = {
bar: "object",
foo: function() {
console.log(this.bar);
}
}
var bar = "global";
obj.foo(); // object
Definição Dinâmica de Contexto
Em JavaScript, a palavra-chave this
function foo() {
var bar = "foo_bar";
console.log(this.bar);
}
const obj1 = { bar: "obj1_bar", foo: foo };
const obj2 = { bar: "obj2_bar", foo: foo };
var bar = "global_bar";
foo(); // "global_bar"
obj1.foo(); // "obj1_bar"
obj2.foo(); // "obj2_bar"
Neste exemplo, a variável global bar
"global_bar"
"foo_bar"
bar
foo
"global_bar"
No caso de objetos, eles definem seu próprio contexto que inclui a propriedade bar
foo
obj1
obj2
Considere outra situação para ilustrar possíveis confusões:
var bar = "global_bar";
const obj1 = {
bar: "obj1_bar",
foo: function() {
console.log(this.bar); // "obj1_bar"
{
{;
const obj2 = { bar: "obj2_bar", foo: obj1.foo }; // "obj2_bar"
const foo = obj1.foo; // Refere-se à função foo definida em obj1
obj1.foo(); // "obj1_bar"
obj2.foo(); // "obj2_bar"
foo(); // "global_bar"
Na situação discutida, a função foo
obj1
const obj1 = {
bar: "obj1_bar",
foo: function() {
console.log(this.bar); // "obj1_bar"
}
};
Aqui, a função foo usa this.bar
bar
obj1
"obj1_bar"
O objeto obj2
obj1
const obj2 = {bar: "obj2_bar", foo: obj1.foo};
Quando obj1.foo
obj2
this.bar
obj2
this.bar
"obj2_bar"
O mesmo acontece quando foo
const foo = obj1.foo;
Neste caso, a função busca this.bar
bar
"global_bar"
Contexto em Funções Aninhadas
Quando uma função é chamada dentro de outra função, o contexto da função interna será o mesmo da função externa, a menos que seja explicitamente modificado:
var bar = "global bar";
function foo() {
var bar = "foo bar";
function moo() {
console.log(this.bar);
}
moo();
}
foo(); // "global bar"
A função moo
foo
foo
"global bar"
Uso de call() e apply()
Esses métodos permitem que você especifique explicitamente o contexto para o qual this deve se referir:
function foo() {
console.log(this.bar);
}
var obj = {bar: "obj_bar"}
var bar = "global_bar";
foo(); // "global_bar"
foo.apply(obj); // "obj_bar"
foo.call(obj); // "obj_bar"
Método bind
O método bind
function foo() {
console.log(this.bar);
}
const obj = {bar: "object"}
var bar = "global";
foo(); // "global"
const func = foo.bind(obj);
func(); // "object"
this e Funções Arrow
Nas funções arrow, o this
const person = {
name: "Tom",
say: () => console.log(`Meu nome é ${this.name}`)
};
person.say(); // "Meu nome é "
Neste exemplo, a função arrow say()
this.name
this
this
Meu nome é
Alteremos um pouco o exemplo:
const person = {
name: "Tom",
hello() {
console.log("Olá");
let say = () => console.log(`Meu nome é ${this.name}`);
say();
}
};
person.hello();
Agora, a função arrow say
hello()
this
person
say
person
this.name
Olá Meu nome é Tom
Apesar de as funções arrow adicionarem algumas complicações no trabalho com this
const school = {
title: "Oxford",
courses: ["JavaScript", "TypeScript", "Java", "Go"],
printCourses() {
this.courses.forEach(function(course) {
console.log(this.title, course);
});
}
};
school.printCourses();
A função printCourses
title
undefined "JavaScript" undefined "TypeScript" undefined "Java" undefined "Go"
O valor de this.title
undefined
this
forEach
school
Uma solução é capturar this
const school = {
title: "Oxford",
courses: ["JavaScript", "TypeScript", "Java", "Go"],
printCourses() {
const that = this;
this.courses.forEach(function(course) {
console.log(that.title, course);
});
}
};
school.printCourses();
Funções arrow oferecem uma abordagem mais elegante:
const school = {
title: "Oxford",
courses: ["JavaScript", "TypeScript", "Java", "Go"],
printCourses() {
this.courses.forEach((course) => console.log(this.title, course));
}
};
school.printCourses();
Com funções arrow, o contexto para a função é sempre o do objeto school