Javascript class calling XMLHttpRequest internally and then handling onreadystatechange
this thing almost works:
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
so it is nothing more than having an XMLHttpRequest object as a member of my class, not globally defined, and calls it in the traditional way. however, inside my callEvent callback function, the "this" value is lost even though the function itself is inside myClass. I also made sure that the object I create from myClass stays long enough (declared global in the script).
in all the javascript class examples I've seen, "this" is still available inside internal functions. for me this is not the case even if I execute my function outside and make it myClass.prototype.connectionEvent. What am I doing wrong? thanks.
a source to share
The reason it doesn't work is because in Javascript it is this
entirely determined by how the function is called, not where it is defined. This is different from some other languages.
To this
mean what you expect, you will need to make sure you explicitly bind to it:
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);
};
More details on this
control in this blog post , but mostly: when a function is called without much effort taken for set this
, this
there will always be a global object inside the function ( window
, in browsers). When making a call, there are two ways to set this
:
- Using
Function#call
(orFunction#apply
), as I did above, we pass an object reference to use as thethis
first parameter. This calls the function and setsthis
to whatever you passed. The difference between#call
and#apply
is how you pass additional arguments to pass to the function. With,#call
you pass them as additional arguments to the call#call
(for example,func.call(thisArg, arg0, arg1, arg2)
), whereas with, you pass them as an#apply
array in the second argument (func.apply(thisArg, [arg0, arg1, arg2])
). - Using dot notation: If you have an object with a function assigned to it (like your property
start
), invoking it with an object instance, dot and property name (this.start()
orfoo.start()
etc.) call the function and set thethis
object instance in the call. So the dotted notation does two very different things: it looks for a property and finds a function as its value, and it calls a function that isthis
set to the object at the time of the call. Just like that:var f = obj.func; f.call(obj)
.
A bit off-topic, but: for a really good reason, I wouldn't reinvent this wheel. There are many libraries for simple XHR calls. jQuery , Prototype , Closure , and just about everyone else.
a source to share