In un file JavaScript ho visto:
function Somefunction(){
var that = this;
...
}
Qual è lo scopo di dichiararlo that
e assegnarglielo this
?
In un file JavaScript ho visto:
function Somefunction(){
var that = this;
...
}
Qual è lo scopo di dichiararlo that
e assegnarglielo this
?
Risposte:
Inizierò questa risposta con un'illustrazione:
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
});
});
La mia risposta inizialmente lo ha dimostrato con jQuery, che è solo leggermente diverso:
$('#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
});
});
Poiché this
cambia frequentemente quando si modifica l'ambito chiamando una nuova funzione, non è possibile accedere al valore originale utilizzandolo. Alias per that
consentire ancora di accedere al valore originale di this
.
Personalmente, non mi piace l'uso that
come alias. Raramente è ovvio a cosa si riferisca, specialmente se le funzioni sono più lunghe di un paio di righe. Ho sempre utilizzare un alias più descrittivo. Nei miei esempi sopra, probabilmente userei clickedEl
.
var self = this;
. La parola that
sembra implicare che la variabile è qualcosa MA this
.
forEach
funzione accetta un secondo argomento facoltativo che è l'associazione della funzione. colours.forEach(function(){/* 'this' is bound correctly --> */}, this);
Quindi dovrebbe essere aggiunta una nota che in realtàvar that = this
non è necessaria . forEach
Da Crockford
Per convenzione, rendiamo privata quella variabile. Questo è usato per rendere l'oggetto disponibile ai metodi privati. Questa è una soluzione alternativa per un errore nelle specifiche del linguaggio ECMAScript che causa l' impostazione errata delle funzioni interne.
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);
Questo avvisa ...
Questo pensa che si chiami Dave
Usi Questo pensa che sia chiamato indefinito
that
variabile non è affatto utilizzata nel suo esempio. Sembra che la sola creazione di una tenuta variabile this
faccia qualcosa per il resto del codice.
Questo è un trucco per far funzionare le funzioni interne (funzioni definite all'interno di altre funzioni) più come dovrebbero. In javascript quando si definisce una funzione all'interno di un'altra this
viene automaticamente impostata sull'ambito globale. Questo può essere fonte di confusione perché ci si aspetta this
che abbia lo stesso valore della funzione esterna.
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();
};
Questo è specificamente un problema quando si crea una funzione come metodo di un oggetto (come car.start
nell'esempio), quindi si crea una funzione all'interno di quel metodo (come activateStarter
). Nel metodo di livello superiore this
punta all'oggetto è un metodo di (in questo caso car
) , ma nella funzione interna this
ora punta all'ambito globale. Questo è un dolore
La creazione di una variabile da usare per convenzione in entrambi gli ambiti è una soluzione per questo problema molto generale con javascript (anche se è utile anche nelle funzioni jquery). Questo è il motivo per cui that
viene usato il nome dal suono molto generale . È una convenzione facilmente riconoscibile per superare un difetto nella lingua.
Come suggerisce El Ronnoco a Douglas Crockford, questa è una buona idea.
L'uso di that
non è veramente necessario se si esegue una soluzione alternativa con l'uso di call()
o 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);
};
A volte this
può fare riferimento a un altro ambito e fare riferimento a qualcos'altro, ad esempio supponiamo di voler chiamare un metodo di costruzione all'interno di un evento DOM, in questo caso this
farà riferimento all'elemento DOM e non all'oggetto creato.
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
La soluzione di cui sopra volontà assing this
per that
poi possiamo e l'accesso alla proprietà nome all'interno del sayHi
metodo da that
, quindi questo può essere chiamato senza problemi all'interno della chiamata DOM.
Un'altra soluzione è quella di assegnare un that
oggetto vuoto e aggiungere proprietà e metodi ad esso e quindi restituirlo. Ma con questa soluzione hai perso il valore prototype
del costruttore.
var Person = function(name) {
var that = {};
that.name = name;
that.sayHi = function() {
alert(that.name);
};
return that;
};
Ecco un esempio `
$(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();
}
});
}
});
});`
Quindi puoi vedere che il valore di questo è due valori diversi a seconda dell'elemento DOM che scegli come target ma quando aggiungi "quello" al codice sopra cambi il valore di "questo" che stai prendendo di mira.
`$(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 ("background-color", "# ffe700"); // Qui il valore di "that" è ".our-work-group> p> a" perché il valore di var that = this; quindi anche se ci troviamo in "this" = '.our-work-single-page', possiamo comunque usare "that" per manipolare il precedente elemento DOM.