classe javascript appeler XMLHttpRequest interne, manipulation puis onreadystatechange
-
26-09-2019 - |
Question
cette chose fonctionne presque:
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
donc rien de plus que d'avoir l'objet XMLHttpRequest en tant que membre de ma classe, au lieu de définir globalement, et en invoquant de la manière traditionnelle. Cependant, dans ma fonction de rappel ConnectionEvent, le sens de « ce » est perdu, même si la fonction elle-même est à l'intérieur scope myClass. J'ai aussi assuré que l'objet que j'instancier de myClass est maintenu en vie assez longtemps (déclarée mondiale dans le script).
dans tous les exemples de l'utilisation des classes javascript que j'ai vu, « ce » était encore disponible à l'intérieur des fonctions internes. pour moi, ce n'est pas, même si je prends ma fonction en dehors et en faire un myClass.prototype.connectionEvent. Qu'est-ce que je fais mal? je vous remercie.
La solution
La raison pour laquelle il ne fonctionne pas est que Javascript, this
est définie entièrement par la façon dont la fonction est appelé , pas là où il est défini. Ceci est différent que d'autres langues.
Pour avoir this
moyenne ce que vous attendez, vous auriez à faire en sorte que explicitement par « liant » il:
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);
};
Il y a plus d'informations sur la gestion des this
ce blog , mais au fond: Lorsqu'une fonction est appelée sans aucun effort particulier fait à this
ensemble, this
dans la fonction sera toujours l'objet global (window
, sur les navigateurs). Il y a deux façons de this
ensemble lors d'un appel:
- Utilisation
Function#call
(ouFunction#apply
) comme je l'ai fait ci-dessus, en passant dans la référence d'objet à utiliser commethis
comme premier paramètre. Qui appelle la fonction et des ensemblesthis
à tout ce que vous avez passé. La différence entre#call
et#apply
est de savoir comment vous fournir d'autres arguments pour passer dans la fonction. Avec#call
vous les fournissez comme d'autres arguments à l'appel#call
(par exemplefunc.call(thisArg, arg0, arg1, arg2)
), alors qu'avec#apply
vous les fournir sous forme de tableau dans le second argument (func.apply(thisArg, [arg0, arg1, arg2])
). - En utilisant la notation en pointillé: Si vous avez un objet qui a une propriété avec une fonction qui lui est assignée (comme votre propriété
start
), appelant à l'aide de l'instance d'objet, d'un point, et le nom de la propriété (this.start()
oufoo.start()
, etc. .) appelle la fonction et jeuthis
à l'instance d'objet dans l'appel. Ainsi, la notation en pointillés fait deux tout à fait distincts choses: recherche la propriété et trouve une fonction de sa valeur, et appelle la fonction telle quethis
est définie sur l'objet pendant l'appel. Littéralement c'est comme:.var f = obj.func; f.call(obj)
Un peu hors-sujet, mais: À moins d'une très bonne raison, je ne réinventer cette roue. Il y a beaucoup de bibliothèques là-bas pour les appels simplement XHR. jQuery , Prototype , Fermeture , et presque tout le reste.