views:

65

answers:

2

I'm new to JavaScript. New as far as all I've really done with it is tweaked existing code and wrote small bits of jQuery.

Now I'm attempting to write a "class" with attributes and methods, but I'm having trouble with the methods. My code:

function Request(destination, stay_open) {
    this.state = "ready";
    this.xhr = null;
    this.destination = destination;
    this.stay_open = stay_open;

    this.open = function(data) {
        this.xhr = $.ajax({
            url: destination,
            success: this.handle_response,
            error: this.handle_failure,
            timeout: 100000000,
            data: data,
            dataType: 'json',
        });
    };

    /* snip... */

}

Request.prototype.start = function() {
    if( this.stay_open == true ) {
        this.open({msg: 'listen'});
    } else {

    }
};
//all console.log's omitted

The problem is, in Request.prototype.start, this is undefined and thus the if statement evaluates to false. What am I doing wrong here?

+4  A: 

How are you calling the start function?

This should work (new is the key)

var o = new Request(destination, stay_open);
o.start();

If you directly call it like Request.prototype.start(), this will refer to the global context (window in browsers).

Also, if this is undefined, it results in an error. The if expression does not evaluate to false.

Update: this object is not set based on declaration, but by invocation. What it means is that if you assign the function property to a variable like x = o.start and call x(), this inside start no longer refers to o. This is what happens when you do setTimeout. To make it work, do this instead:

 var o = new Request(...);
 setTimeout(function() { o.start(); }, 1000);
Chetan Sastry
I am using setTimeout: `var listen = new Request(destination, stay_open); setTimeout(listen.start, 500);`
Carson Myers
Yes, that would not work. I will update my answer.
Chetan Sastry
excellent, thank you
Carson Myers
A: 

JavaScript's OOP is a little funky (or a lot) and it takes some getting used to. This first thing you need to keep in mind is that there are no Classes and thinking in terms of classes can trip you up. And in order to use a method attached to a Constructor (the JavaScript equivalent of a Class definition) you need to instantiate your object. For example:

Ninja = function (name) {
    this.name = name;
};
aNinja = new Ninja('foxy');
aNinja.name; //-> 'foxy'

enemyNinja = new Ninja('boggis');
enemyNinja.name; //=> 'boggis'

Note that Ninja instances have the same properties but aNinja cannot access the properties of enemyNinja. (This part should be really easy/straightforward) Things get a bit different when you start adding stuff to the prototype:

Ninja.prototype.jump = function () {
   return this.name + ' jumped!';
};
Ninja.prototype.jump(); //-> Error.
aNinja.jump(); //-> 'foxy jumped!'
enemyNinja.jump(); //-> 'boggis jumped!'

Calling this directly will throw an error because this only points to the correct object (your "Class") when the Constructor is instantiated (otherwise it points to the global object, window in a browser)

indieinvader