0

I have two huge issues with this scope in my javascript code. After creating setAJAXGet object, callback function was lost and couldn't be called correctly. So instead of calling this.funct I set ajax.parent = this; and call this.parent.funct - works ok.

function setAJAXGet() {
    this.askServer = function() {
    var ajax = new XMLHttpRequest();
    ajax.parent = this; 
    ajax.contentType = "charset:utf-8";
    ajax.onreadystatechange = function() {
            if (ajax.readyState==4 && ajax.status==200) {
            this.parent.funct(ajax.responseText);
            }
    }
    ajax.open( "GET", this.url+'?'+this.vars, true );
    ajax.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
    if (navigator.onLine) ajax.send( null ); else this.functError();
    }
this.functError;
this.funct;
this.vars;
this.url;
}

Things get a little more complicated when I try to call setAJAXGet() from the other object and the callback function is inside that object. Callback function is called correctly, but every other function in the object (from the callback function) gets invisible.

function someObject() {
    this.asyncGet = function() {
    var get = new setAJAXGet();
    //do some config here...
    get.funct = this.processAsyncData;
    get.askServer();
    }

    this.someOtherFunction = function() {
    }

    this.processAsyncData = function(ajaxText) {
    // ajaxText is OK
    this.someOtherFunction();
    // this.someOtherFunction is not defined (how so?)
    }

this.asyncGet();
}

I can solve this problem by passing object to the processAsyncData by modified setAJAXGet() as argument, but it looks ugly.

function someObject() {
    this.asyncGet = function() {
    var get = new modifiedSetAJAXGet();
    //do config here...
    get.object = this; // stores 'this' and sends it to callback as argument
    get.funct = this.processAsyncData;
    get.askServer();
    }

    this.someOtherFunction = function() {
    }

    this.processAsyncData = function(object, ajaxText) {
    // ajaxText is OK
    object.someOtherFunction();
    // object.someOtherFunction works just fine
    }

this.asyncGet();
}

I believe that you know more elegant solution.

1 Answers1

0

It is hard to follow the objective of your code, but the main thing you need to learn in Javascript is that the value of this within a function is controlled by how the function is called. This is confusing in Javascript until you fully grok that all that matters is how the function is called. It doesn't matter how things are declared, only how they are called.

When you do something like this:

get.funct = this.processAsyncData;

What gets put into get.funct is a pointer to the processAsyncData method. There is no connection at all to the this value in get.funct any more. So, when sometime later you call get.funct(), it will not be the same as calling this. processAsyncData(). The value of this will be lost.

This is where .bind() comes in handy. You can read about .bind here. What it does is to create a temporary function stub that reattaches your value of this so that the above separation does not happen. So, you could use it like this:

get.funct = this.processAsyncData.bind(this);

Then, when you call get.funct(), it will generate exactly the same function call and value of this as this.processAsyncData() would because the .bind() has created a function stub to automatically reattach the desired value of this.

As I posted in an earlier comment, there's a very good summary of how the value of this is controlled in this other answer: When you pass 'this' as an argument.

Note, my proposed solution is different than what you mentioned in your comment. I'm suggesting that you fix the problem earlier in the process so then the .funct method can be called by anyone at any time without having to do something special.

Community
  • 1
  • 1
jfriend00
  • 580,699
  • 78
  • 809
  • 825