Em um arquivo JavaScript, vi:
function Somefunction(){
var that = this;
...
}
Qual é o propósito de declarar that
e atribuir this
isso a ele?
Em um arquivo JavaScript, vi:
function Somefunction(){
var that = this;
...
}
Qual é o propósito de declarar that
e atribuir this
isso a ele?
Respostas:
Vou começar esta resposta com uma ilustração:
var colours = ['red', 'green', 'blue'];
document.getElementById('element').addEventListener('click', function() {
// this is a reference to the element clicked on
var that = this;
colours.forEach(function() {
// this is undefined
// that is a reference to the element clicked on
});
});
Minha resposta originalmente demonstrou isso com o jQuery, que é apenas um pouco diferente:
$('#element').click(function(){
// this is a reference to the element clicked on
var that = this;
$('.elements').each(function(){
// this is a reference to the current element in the loop
// that is still a reference to the element clicked on
});
});
Como this
frequentemente muda quando você altera o escopo chamando uma nova função, não é possível acessar o valor original usando-o. Aliasing para that
permite que você ainda acesse o valor original de this
.
Pessoalmente, não gosto do uso de that
como apelido. Raramente é óbvio a que se refere, especialmente se as funções tiverem mais de duas linhas. Eu sempre uso um alias mais descritivo. Nos meus exemplos acima, eu provavelmente usaria clickedEl
.
var self = this;
. A palavra that
parece implicar que a variável é qualquer coisa, MAS this
.
forEach
função recebe um segundo argumento opcional: qual é a ligação da função. colours.forEach(function(){/* 'this' is bound correctly --> */}, this);
Portanto, uma nota deve ser adicionada que var that = this
não é realmente necessária forEach
.
A partir de Crockford
Por convenção, tornamos privada essa variável. Isso é usado para disponibilizar o objeto para os métodos privados. Esta é uma solução alternativa para um erro na especificação de idioma ECMAScript que faz com que isso seja definido incorretamente para funções internas.
function usesThis(name) {
this.myName = name;
function returnMe() {
return this; //scope is lost because of the inner function
}
return {
returnMe : returnMe
}
}
function usesThat(name) {
var that = this;
this.myName = name;
function returnMe() {
return that; //scope is baked in with 'that' to the "class"
}
return {
returnMe : returnMe
}
}
var usesthat = new usesThat('Dave');
var usesthis = new usesThis('John');
alert("UsesThat thinks it's called " + usesthat.returnMe().myName + '\r\n' +
"UsesThis thinks it's called " + usesthis.returnMe().myName);
Isso alerta ...
Que pensa que se chama Dave
Isso acha que é chamado de indefinido
that
variável não é usada em seu exemplo. Faz parecer que apenas criar uma retenção de variável this
faz algo com o restante do código.
Este é um truque para fazer com que as funções internas (funções definidas dentro de outras funções) funcionem mais como deveriam. Em javascript, quando você define uma função dentro de outra, this
automaticamente é definido para o escopo global. Isso pode ser confuso porque você espera this
ter o mesmo valor que na função externa.
var car = {};
car.starter = {};
car.start = function(){
var that = this;
// you can access car.starter inside this method with 'this'
this.starter.active = false;
var activateStarter = function(){
// 'this' now points to the global scope
// 'this.starter' is undefined, so we use 'that' instead.
that.starter.active = true;
// you could also use car.starter, but using 'that' gives
// us more consistency and flexibility
};
activateStarter();
};
Isso é especificamente um problema quando você cria uma função como método de um objeto (como car.start
no exemplo) e depois cria uma função dentro desse método (como activateStarter
). No nível superior, o método this
aponta para o objeto e é um método de (neste caso car
) , mas na função interna this
agora aponta para o escopo global. Isso é uma dor.
Criar uma variável a ser usada por convenção nos dois escopos é uma solução para esse problema muito geral com javascript (embora seja útil também nas funções jquery). É por isso que o nome sonoro muito geral that
é usado. É uma convenção facilmente reconhecível para superar uma falha no idioma.
Como El Ronnoco sugere em Douglas Crockford, essa é uma boa idéia.
O uso de that
não é realmente necessário se você fizer uma solução alternativa com o uso de call()
ou apply()
:
var car = {};
car.starter = {};
car.start = function(){
this.starter.active = false;
var activateStarter = function(){
// 'this' now points to our main object
this.starter.active = true;
};
activateStarter.apply(this);
};
Às vezes, this
pode se referir a outro escopo e a outra coisa, por exemplo, suponha que você queira chamar um método construtor dentro de um evento DOM, nesse caso, this
se referirá ao elemento DOM e não ao objeto criado.
HTML
<button id="button">Alert Name</button>
JS
var Person = function(name) {
this.name = name;
var that = this;
this.sayHi = function() {
alert(that.name);
};
};
var ahmad = new Person('Ahmad');
var element = document.getElementById('button');
element.addEventListener('click', ahmad.sayHi); // => Ahmad
A solução acima irá assing this
para that
, em seguida, podemos e acesso a propriedade de nome dentro do sayHi
método a partir that
, de modo que este pode ser chamado sem problemas dentro da chamada DOM.
Outra solução é atribuir um that
objeto vazio e adicionar propriedades e métodos a ele e depois devolvê-lo. Mas com esta solução, você perdeu prototype
o construtor.
var Person = function(name) {
var that = {};
that.name = name;
that.sayHi = function() {
alert(that.name);
};
return that;
};
Aqui está um exemplo `
$(document).ready(function() {
var lastItem = null;
$(".our-work-group > p > a").click(function(e) {
e.preventDefault();
var item = $(this).html(); //Here value of "this" is ".our-work-group > p > a"
if (item == lastItem) {
lastItem = null;
$('.our-work-single-page').show();
} else {
lastItem = item;
$('.our-work-single-page').each(function() {
var imgAlt = $(this).find('img').attr('alt'); //Here value of "this" is '.our-work-single-page'.
if (imgAlt != item) {
$(this).hide();
} else {
$(this).show();
}
});
}
});
});`
Assim, você pode ver que esse valor é de dois valores diferentes, dependendo do elemento DOM que você segmentar, mas quando você adiciona "that" ao código acima, altera o valor de "this" que está direcionando.
`$(document).ready(function() {
var lastItem = null;
$(".our-work-group > p > a").click(function(e) {
e.preventDefault();
var item = $(this).html(); //Here value of "this" is ".our-work-group > p > a"
if (item == lastItem) {
lastItem = null;
var that = this;
$('.our-work-single-page').show();
} else {
lastItem = item;
$('.our-work-single-page').each(function() {
***$(that).css("background-color", "#ffe700");*** //Here value of "that" is ".our-work-group > p > a"....
var imgAlt = $(this).find('img').attr('alt');
if (imgAlt != item) {
$(this).hide();
} else {
$(this).show();
}
});
}
});
});`
..... $ (that) .css ("cor de fundo", "# ffe700"); // Aqui o valor "that" é ".our-work-group> p> a" porque o valor de var that = this; portanto, mesmo estando em "this" = '.our-work-single-page', ainda podemos usar "that" para manipular o elemento DOM anterior.