Classe javascript chiamando XMLHttpRequest internamente, quindi la manipolazione onreadystatechange
-
26-09-2019 - |
Domanda
questa cosa quasi funziona:
function myClass(url) {
this.source = url;
this.rq = null;
this.someOtherProperty = "hello";
// open connection to the ajax server
this.start = function() {
if (window.XMLHttpRequest) {
this.rq = new XMLHttpRequest();
if (this.rq.overrideMimeType)
this.rq.overrideMimeType("text/xml");
} else
this.rq = new ActiveXObject("Microsoft.XMLHTTP");
try {
this.rq.onreadystatechange = connectionEvent;
this.rq.open("GET", this.source, true);
this.rq.send(null);
this.state = 1;
} catch (err) {
// some error handler here
}
}
function connectionEvent() {
alert("i'm here");
alert("this doesnt work: " + this.someOtherProperty);
}
} // myClass
Quindi è altro che abbia per oggetto XMLHttpRequest come membro della mia classe, anziché globalmente definito, e invocando nel modo tradizionale. tuttavia, dentro la mia funzione di callback ConnectionEvent, il significato di "questo" si perde, anche se la funzione stessa è ambito all'interno myClass. Ho anche fatto in modo che l'oggetto che ho un'istanza di da myClass è mantenuto abbastanza a lungo in vita (dichiarata globale nello script).
In tutti gli esempi di utilizzo di classi JavaScript che ho visto, "questo" era ancora disponibile all'interno delle funzioni interne. per me, non lo è, anche se prendo la mia funzione di fuori e ne fanno un myClass.prototype.connectionEvent. Che cosa sto facendo di sbagliato? grazie.
Soluzione
La ragione che non funziona è che in Javascript, this
è definita interamente dal modo in cui una funzione è chiamato , non dove è definito. Questo è diverso rispetto ad alcune altre lingue.
Per avere this
dire quello che ci si aspetta, che avrebbe dovuto garantire che in modo esplicito dal "legame" che:
this.start = function() {
var self = this; // Set up something that survives into the closure
/* ...lots of stuff omitted... */
this.rq.onreadystatechange = function() {
// Call `connectionEvent`, setting `self` as `this` within the call
connnectionEvent.call(self);
};
C'è ulteriori informazioni sulla gestione this
in questo post del blog , ma fondamentalmente: Quando viene chiamata una funzione senza particolare sforzo per this
set, this
all'interno della funzione sarà sempre l'oggetto globale (window
, sui browser). Ci sono due modi per this
insieme Quando si effettua una chiamata:
- Uso
Function#call
(oFunction#apply
) come ho fatto sopra, passando il riferimento all'oggetto da utilizzare comethis
come primo parametro. Che chiama la funzione e impostathis
a tutto ciò che avete passato. La differenza tra#call
e#apply
è il modo per fornire ulteriori argomenti da passare alla funzione. Con#call
li forniti come ulteriori argomenti alla chiamata#call
(ad esempiofunc.call(thisArg, arg0, arg1, arg2)
), mentre con#apply
loro fornite come un array nel secondo argomento (func.apply(thisArg, [arg0, arg1, arg2])
). - Utilizzo di notazione: se si dispone di un oggetto che ha una proprietà con una funzione ad esso assegnata (come la vostra proprietà
start
), definendolo utilizzando l'istanza dell'oggetto, un punto, e il nome della proprietà (this.start()
ofoo.start()
, ecc .) chiamerà la funzione e impostarethis
all'istanza oggetto all'interno della chiamata. Così la notazione fa due del tutto distinti le cose: guarda in alto la proprietà e trova una funzione come il suo valore, e chiama la funzione in modo tale chethis
è impostato per l'oggetto durante la chiamata. Letteralmente è come:.var f = obj.func; f.call(obj)
Un po 'off-topic, ma: A meno di un buon motivo per, non vorrei reinventare questa ruota. Ci sono un sacco di librerie là fuori per le chiamate semplicemente XHR. jQuery , Prototype , chiusura , e quasi tutto il resto.