-1

I know that this references to the object owner. But I'm having a hard time trying to make a class work, while trying to identify what this is referencing to.

Guess it's best to just show the code:

function Ajax_Class(params) {
// Public Properties
this.Response = null;

// Private Properties
var RequestObj = null;

// Prototype Methods
this.OnReset    = function() { };
this.OnOpenConn = function() { };
this.OnDataSent = function() { };
this.OnLoading  = function() { };
this.OnSuccess  = function() { alert("default onSuccess method."); };
this.OnFailure  = function() { alert("default onFailure method."); };

// Public Methods
this.Close = function() {   // Abort current Request
    if (RequestObj) {
        RequestObj.abort();
        RequestObj = null;
        return true;
    } else return false;
};

// Private Methods
var Instance = function() {     // To create instance of Http Request
    try { return new XMLHttpRequest(); }
    catch (error) {}
    try { return new ActiveXObject("Msxml2.XMLHTTP"); }
    catch (error) {}
    try { return new ActiveXObject("Microsoft.XMLHTTP"); }
    catch (error) {}

    // throw new Error("Could not create HTTP request object.");
    return false;
};

var ReadyStateHandler = function() {
    // Switch through possible results
    switch(RequestObj.readyState) {
        case 0:
            this.OnReset();
        break;

        case 1:
            this.OnOpenConn();
        break;

        case 2:
            this.OnDataSent();
        break;

        case 3:
            this.OnLoading();
        break;

        case 4:
            // Check Status
            if (RequestObj.status == 200)  {
                // Handle Response
                Response = HandleResponse();
                // Call On Success
                this.OnSuccess();
                // Hide Loading Div
                LoadingDiv(true);
            } else {
                this.OnFailure();
            }

        break;
    } // End Switch
};

var Open = function() {
    // In case it's XML, Override the Mime Type
    if ((params["ResponseType"] == "XML") && (RequestObj.overrideMimeType)) 
        RequestObj.overrideMimeType('text/xml');

    // 
    if ((params["User"]) && (params["Password"]))
        RequestObj.open(params["Method"], params["URL"],  params["Async"], params["User"], params["Password"]);
    else if (params["User"])
        RequestObj.open(params["Method"], params["URL"],  params["Async"], params["User"]);
    else
        RequestObj.open(params["Method"], params["URL"],  params["Async"]);

    // Set Request Header ?
    if (params["method"] == "POST") 
        //this.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        RequestObj.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

};

var Send = function() {
    if (params["Data"])     RequestObj.send(params["Data"]);
    else                    RequestObj.send(null);
};

var HandleResponse = function() {
    if (params["ResponseType"] == "JSON")
        return ParseJSON(RequestObj.responseText);
    else if (params["ResponseType"] == "XML")
        return RequestObj.responseXML;
    else 
        return RequestObj.responseText;
};

// Method ParseJSON
var ParseJSON = function(obj) {
    if (obj)
        return JSON.parse(obj);
}; // End ParseJSON

// Method LoadingDiv -> Either Shows or Hides the Loading Div
var LoadingDiv = function(hide) {
    // Hide the Modal Window
    if (hide) { document.getElementById("Async").style.display = "none"; return false; }

    // Show Modal Window
    document.getElementById("Async").style.display = "block";

    // Reset the Position of the Modal_Content to 0, x and y
    document.getElementById("Async_Container").style.left = "0px";
    document.getElementById("Async_Container").style.top = "0px";

    // Center the Modal Area, no matter what the content
    var Screen_Width, Screen_Height;
        // Get screen data
        if (typeof(window.innerWidth) == "number") { Screen_Width = window.innerWidth; Screen_Height = window.innerHeight; }            //Non-IE
        else if (document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) {         //IE 6+ in 'standards compliant mode'
            Screen_Width = document.documentElement.clientWidth;
            Screen_Height = document.documentElement.clientHeight;
        } else if (document.body && (document.body.clientWidth || document.body.clientHeight)) {                                        //IE 4 compatible
            Screen_Width = document.body.clientWidth;
            Screen_Height = document.body.clientHeight;
        }

        // Set Modal_Content Max Height to allow overflow
        document.getElementById("Async_Container").style.maxHeight = Screen_Height - 200 + "px";

        // Get Modal_Container data
        var El_Width = document.getElementById("Async_Container").offsetWidth;
        var El_Height = document.getElementById("Async_Container").offsetHeight;


    // Set the Position of the Modal_Content
    document.getElementById("Async_Container").style.left = ((Screen_Width/2) - (El_Width/2)) + "px";
    document.getElementById("Async_Container").style.top = ((Screen_Height/2) - (El_Height/2)) + "px";
};


// Constructor

// Check the Params
// Required Params
if (!params["URL"]) return false;
// Default Params
params["Method"]        = (!params["Method"]) ? "GET" : params["Method"];   // GET, POST, PUT, PROPFIND
params["Async"]         = (params["Async"] === false) ? false : true;
params["ResponseType"]  = (!params["ResponseType"]) ? "JSON" : params["ResponseType"];  // JSON, TXT, XML
params["Loading"]       = (params["Loading"] === false) ? false : true;
// Optional Params
// params["User"])
// params["Password"]

// Create Instance of Http Request Object
RequestObj = Instance();

// Handle Ajax according to Async
if (params["Async"]) {
    // Handle what should be done in case readyState changes
    if (params["Loading"]) LoadingDiv();
    // State Handler || Response is Handled within the code
    RequestObj.onreadystatechange = ReadyStateHandler;
    // Open & Send
    Open();
    Send();
} else {
    // Handle the Loading Div
    if (params["Loading"]) LoadingDiv();
    // Open & Send
    Open();
    Send();
    // Handle Response
    this.Response = HandleResponse();
    // No State Handler, Application has been waiting for modifications.
    //this.OnSuccess(Response);
    // Handle the Loading Div
    LoadingDiv(true);
}

// no problems?
return true;

} // End Ajax

Then, inside the page:

window.onload = function() {

update_states = function() {
    this.OnSuccess = function() {
        alert("overriden onSuccess Method");
    };
};
    update_states.prototype = new Ajax_Class({URL:"ajax/states.php?id=5&seed="+Math.random()});
    run_update_states = new update_states;      

} // Window Onload

What I'm trying to do is have a Default OnSuccess (and etc.) Method, and, in case there's need, I can override the default methods with the subclass method, but it will still be called automatically upon HttpRequest state change.

I'd appreciate if someone could point me in the right direction, and would be amazed if I could ever understand why this isn't working in this circunstance and how to make it reference to the correct object.

Thanks for any help.

13
  • console.log(this) in Firefox or Chrome helps out in determining what this refers to in a certain part of your code (scope). Also, this isn't the object owner, its the object itself. Another handy tip is using typeof(this) or this.constructor to get more info on the object. Commented Sep 6, 2012 at 22:48
  • I see. The way it is, this.OnSuccess if pointing to the object xmlHttpRequest. Makes sense, based on what you say. But when I tried, while on the Class block, something like: var self = this; then I couldn't override the Class Methods, because it would always be referring to the main class. Does that make any sense? Commented Sep 6, 2012 at 22:54
  • I did what Jfriend00 said: function Ajax_Class() { var self = this; (...) then tried, on state change: self.OnSuccess(); then it will always call the default class OnSuccess function, not the one I set on the subclass... Commented Sep 6, 2012 at 23:00
  • I'm glad you solved it. For prototyping and scope resolution, try this resource. "The Resolution of Property Names on Objects" section. Commented Sep 6, 2012 at 23:02
  • @MalSu—this has nothing to do with scope, they are completely different things. In ES5 strict mode, this can be anything, even undefined or null. Kudos though for referencing Richard Cornford. Commented Sep 6, 2012 at 23:02

3 Answers 3

1

this is set according to how something is called. These are the different ways it is set:

  1. func() - A normal function call. this is set to the global object (window in a browser) .

  2. obj.method() - A method call. this is set to obj.

  3. func.call(obj, arg1, arg2, ...) - using .call(). this is set to obj.

  4. func.apply(obj, args) - using .apply(). this is set to obj.

  5. func.bind(obj, arg1, arg2, ...) - using .bind(). Creates a new function that sets this to obj when called (internally, it uses .apply() in its implementation).

Typical things to watch out for.

  • Calling a regular function, even from within an object's method will cause the this pointer to be window inside that function.
  • A callback function will typically receive a different this value than the code it might be embedded in. You may have to save the original this value into a local variable (often called self by convention) so you can refer to it from your callback function.
Sign up to request clarification or add additional context in comments.

5 Comments

note that call, apply, and, more recently, bind, can all change the context of this to whatever you want, the latter doing so without executing the function.
@leemachin - I added .bind() - already had .call() and .apply().
I appreciate your answer. But this is confusing me, actually. So what's the expected behavior of this when I create a new instance of an object?
@IgorDonin - Your question only has 1/3 the information needed to answer. If you create a new object called myObject and call a method on that object with myObject.print(), then this will be set to myObject inside the print() method for that specific call. If you have a different object yourObject and you call yourObject.print(), then this will be set to yourObject inside that specific execution of the print method. It is the caller that determines how this is set.
My question has the entire class and the objects instantiation. It's all there, mate. update_state is a class that uses Ajax_Class as a prototype and has a OnSuccess method that overrides the prototype's. run_update_state creates an instance of update_state, which gets a response of a http request and handles it. What I want is the method OnSuccess of the update_state to be run instead of the prototype's method.
1

Perhaps you are trying to do something like:

function Base() {}

Base.prototype.showName = function() {
  alert('Base method: ' + this.name);
}

function Foo(name, arg){

   this.name = name;

  // Extend this if arg is an object
  if (typeof arg == 'object') {
    for (var p in arg) {

      // This references the new instance if called with new keyword
      if (arg.hasOwnProperty(p)) {
        this[p] = arg[p];
      }
    }
  }
}

Foo.prototype = new Base();

// Re-assign constructor property (not very useful but some to do like this)
Foo.prototype.constructor = Foo; 

var inst0 = new Foo('foo 0');

// Override inherited method
var inst1 = new Foo(
             'foo 1',
             {showName: function(){alert('Instance method: ' + this.name);}}
            );

inst0.showName(); // Base method: foo 0
inst1.showName(); // Instance method: foo 1

But there are other (simpler? better?) ways of doing that. Make prototype inheritance and javascript's dynamic nature work for you, don't try to make it emulate other inheritance patterns just because you're more comfortable with them.

1 Comment

It took me a while to see the wisdom in your answer. Cheers, mate.
0

have you tried this

run_update_states = new update_states();

notice the parentheses.

2 Comments

thanks for your answer, mate. I tested it, but no go. What's the expected result when you create an instance of an object and run a function at the same time? Does the object run_update_states get created?
if this is not a problem to you script, you can pass the function that you need onSuccesss as a parameter to the AjaxClass and add it to the object if it exists.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.