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.

+2


a source to share


1 answer


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

    (or Function#apply

    ), as I did above, we pass an object reference to use as the this

    first parameter. This calls the function and sets this

    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()

    or foo.start()

    etc.) call the function and set the this

    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 is this

    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.

+4


a source







All Articles