4

How do I call class methods from functions within the class? My code is:

var myExtension = {

    init: function() {
        // Call onPageLoad
    },  

    onPageLoad: function() {  
        // Do something    
    },

}  

I've tried ...

onPageLoad();

... from within the init method but it's saying it's not defined.

I'm not having much luck with google because I don't understand the syntax used. All the JS OOP examples I find online are in a different format. I'm using the format Mozilla use for extension development.

  • Watch out for trailing commas after the onPageLoad function. IE8 and below can't handle them. – Joe Nov 15 '11 at 01:15

4 Answers4

7

The object the current method was invoked on is available via the special variable this. Any time you call a method on an object, this will refer, within the method, to the object.

var myExtension = {

    init: function() {
        this.onPageLoad();
    },  

    onPageLoad: function() {  
        // Do something    
    },

};

this always refers to the calling object rather than the object the function is defined on or is a property of.

value = 'global';
var ob0 = {
        value: 'foo',
        val: function() {
            return this.value;
        },
    },
    ob1 = {value: 'bar'},
    ob2 = {value: 'baz'};

ob0.val(); // 'foo'
ob1.val = ob0.foo;
ob1.val(); // 'bar'
ob0.val.call(ob2); // 'baz'

var val = ob0.val;
val(); // 'global'

In the last case, val is executed as a free function (a function that isn't bound to an object, i.e. not a method), in which case this takes on the value of the global object (which is window in web browsers) within the execution of val. Global variables are actually properties of the global object, hence val() returns 'global' (the value of the global variable named value). Since global variables are actually properties of the global object, you can view free functions as actually being methods of the global object. From this viewpoint, the last two lines (when executed in global scope) are equivalent to:

window.val = ob0.val;
window.val();

This viewpoint doesn't exactly match the reality of scoping, though you'll only notice the difference within functions. In a function, window.val = ... will create a global while var val won't.

value = 'global';
var ob0 = {
        value: 'foo',
        val: function() {
            return this.value;
        },
    };

function lcl() {
    var val = ob0.val; // doesn't set a global named `val`
    return val(); // 'global'
}
lcl(); // 'global'
val(); // error; nothing named 'val'

function glbl() {
    window.val = ob0.val; // sets a global named `val`
    return window.val();  // 'global'
}
glbl(); // 'global'
val(); // 'global'

See MDN's reference page for more on the call method used above. For more on the this variable, see "JavaScript “this” keyword" and "How does “this” keyword work within a JavaScript object literal?"

Community
  • 1
  • 1
outis
  • 68,704
  • 19
  • 132
  • 197
6

Assuming that you have called init like this:

myExtension.init();

then it should be:

init: function() {
    // before
    this.onPageLoad();
    // after
}

But in Javascript functions are not actually bound to objects and you can call any function on any other object, like this:

myExtension.init.call(anotherObject); // or
myExtension.init.apply(anotherObject);

In this example this within init would be anotherObject, which doesn't have onPageLoad defined. If you want to support this kind of usage you'll have to manually reference the initial object:

init: function() {
    // before
    myExtension.onPageLoad();
    // after
}
deviousdodo
  • 9,023
  • 2
  • 27
  • 33
2

In Javascript you need to explicitly mention the this

this.onPageLoad()

The same is also true for other member variables (remember that in Javascript methods are just member variables that happen to be functions)

this.memberVariable
hugomg
  • 63,082
  • 19
  • 144
  • 230
  • I've tried that, it's still saying it's undefined. This is why I'm puzzled. – James Guvna Jeffery Nov 15 '11 at 01:07
  • @JamesGuvnaJeffery: `this` is actually kind of tricky in Javascript and is a very common source of headaches. You should try to provide a running example like mellamokb did. – hugomg Nov 15 '11 at 01:09
0

Have you considered a closure, instead?

For example:

var myExtension = ( function() {

    var me = {};

    var private_thingy = "abcDEFG123";


    var onPageLoad = function() {
        // do page loading business
        alert( private_thingy );
    }
    me.onPageLoad = onPageLoad;


    var init = function() {
        onPageLoad();
    }
    me.init = init;


    return me;

})();

///////////////

myExtension.private_thingy = "DIDDLED!";
// will NOT modify the private_thingy declared within the closure

myExtension.init(); // will work fine.

Anything you define within the closure is available within the closure at all times, and when implemented carefully will yield private members not accessible to users of the object. Only members that you explicitly export - e.g., the me.xxx = xxx lines - are publicly available.

Thus, when onPageLoad executes, "abcDEFG123" will be displayed in the alert, not "DIDDLED!". Users of the object can modify properties using the dot operator until the cows come home; what's not made public by the closure, however, can never be modified: even if the user reassigns a function on the public interface, calls to the private function from within the closure will always point to the function defined within the closure.

The important part: it unties you from the constant use of this (unless you really want to use it; save your fingers for more important typing!).

Give it a shot. And have a look at Javascript: The Good Parts by Crockford.

Christopher
  • 754
  • 4
  • 6