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 thisem 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 selfe 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 thisvalor do retorno de chamada.
Conjunto explicitamente thisdo retorno de chamada - parte 1
Pode parecer que você não tem controle sobre o valor de thisporque 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 thisvinculada a um valor. A função tem exatamente o mesmo comportamento que você chamou .bind, apenas que thisfoi definido por você. Não importa como ou quando essa função é chamada, thissempre 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 thisao 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 thisligaçã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 thisdo 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 thisdevem 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 thisdeve 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 thisgeralmente é mencionado na documentação dessa função / método. Por exemplo, o $.ajaxmé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.bodyfor clicado, o valor registrado será undefined, porque dentro do manipulador de eventos thisse refere à document.bodyinstância, e não à instância Foo.
Como já mencionado no início, o que thisse 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 .bindpara ligar explicitamente thisa 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();