O que você deve saber sobre this
this
(também conhecido como "o contexto") é uma palavra-chave especial dentro de cada função e seu valor depende apenas de como a função foi chamada, não de como / quando / onde foi definida. Não é afetado por escopos lexicais como outras variáveis (exceto para funções de seta, veja abaixo). aqui estão alguns exemplos:
function foo() {
console.log(this);
}
// normal function call
foo(); // `this` will refer to `window`
// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`
// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`
Para saber mais this
, consulte a documentação do MDN .
Como se referir ao correto this
Não use this
Você realmente não deseja acessar this
em particular, mas o objeto a que se refere . É por isso que uma solução fácil é simplesmente criar uma nova variável que também se refere a esse objeto. A variável pode ter qualquer nome, mas os comuns são self
e that
.
function MyConstructor(data, transport) {
this.data = data;
var self = this;
transport.on('data', function() {
alert(self.data);
});
}
Como self
é uma variável normal, ela obedece às regras de escopo lexical e é acessível dentro do retorno de chamada. Isso também tem a vantagem de poder acessar o this
valor do retorno de chamada.
Conjunto explicitamente this
do retorno de chamada - parte 1
Pode parecer que você não tem controle sobre o valor de this
porque seu valor é definido automaticamente, mas esse não é realmente o caso.
Toda função possui o método .bind
[docs] , que retorna uma nova função this
vinculada a um valor. A função tem exatamente o mesmo comportamento que você chamou .bind
, apenas que this
foi definido por você. Não importa como ou quando essa função é chamada, this
sempre se refere ao valor passado.
function MyConstructor(data, transport) {
this.data = data;
var boundFunction = (function() { // parenthesis are not necessary
alert(this.data); // but might improve readability
}).bind(this); // <- here we are calling `.bind()`
transport.on('data', boundFunction);
}
Nesse caso, estamos vinculando os retornos de chamada this
ao valor de MyConstructor
's this
.
Nota: Ao vincular o contexto para jQuery, use jQuery.proxy
[docs] . O motivo para fazer isso é que você não precisa armazenar a referência à função ao desvincular um retorno de chamada de evento. O jQuery lida com isso internamente.
O ECMAScript 6 apresenta funções de seta , que podem ser consideradas funções lambda. Eles não têm sua própria this
ligação. Em vez disso, this
é pesquisado no escopo como uma variável normal. Isso significa que você não precisa ligar .bind
. Esse não é o único comportamento especial que eles têm; consulte a documentação do MDN para obter mais informações.
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => alert(this.data));
}
Conjunto this
do retorno de chamada - parte 2
Algumas funções / métodos que aceitam retornos de chamada também aceitam um valor ao qual os retornos de chamada this
devem se referir. Isso é basicamente o mesmo que vincular você mesmo, mas a função / método faz isso por você. Array#map
[docs] é esse método. Sua assinatura é:
array.map(callback[, thisArg])
O primeiro argumento é o retorno de chamada e o segundo argumento é o valor ao qual this
deve se referir. Aqui está um exemplo artificial:
var arr = [1, 2, 3];
var obj = {multiplier: 42};
var new_arr = arr.map(function(v) {
return v * this.multiplier;
}, obj); // <- here we are passing `obj` as second argument
Nota: Se você pode ou não passar um valor this
geralmente é mencionado na documentação dessa função / método. Por exemplo, o $.ajax
método do jQuery [docs] descreve uma opção chamada context
:
Este objeto será transformado no contexto de todos os retornos de chamada relacionados ao Ajax.
Problema comum: Usando métodos de objeto como retornos de chamada / manipuladores de eventos
Outra manifestação comum desse problema é quando um método de objeto é usado como manipulador de retorno de chamada / evento. Funções são cidadãos de primeira classe em JavaScript e o termo "método" é apenas um termo coloquial para uma função que é um valor de uma propriedade de objeto. Mas essa função não tem um link específico para seu objeto "contendo".
Considere o seguinte exemplo:
function Foo() {
this.data = 42,
document.body.onclick = this.method;
}
Foo.prototype.method = function() {
console.log(this.data);
};
A função this.method
é atribuída como manipulador de eventos de clique, mas se document.body
for clicado, o valor registrado será undefined
, porque dentro do manipulador de eventos this
se refere à document.body
instância, e não à instância Foo
.
Como já mencionado no início, o que this
se refere depende de como a função é chamada , não de como é definida .
Se o código fosse o seguinte, pode ser mais óbvio que a função não tenha uma referência implícita ao objeto:
function method() {
console.log(this.data);
}
function Foo() {
this.data = 42,
document.body.onclick = this.method;
}
Foo.prototype.method = method;
A solução é a mesma mencionada acima: Se disponível, use .bind
para ligar explicitamente this
a um valor específico
document.body.onclick = this.method.bind(this);
ou chame explicitamente a função como um "método" do objeto, usando uma função anônima como retorno de chamada / manipulador de eventos e atribua o objeto ( this
) a outra variável:
var self = this;
document.body.onclick = function() {
self.method();
};
ou use uma função de seta:
document.body.onclick = () => this.method();