Question

I use SWFAddress for deep linking my site (link to SWFAddress). I like to break code into classes so I have a main structure similar to this:

function SomeClass() {
    //this adds the this.handleChange() function to the
    //SWFAddress event listener
    this.initializeSWFA = function() {
        //SWFAddress variable is instantiated in SWFAddress javascript file
        //so I can use it here
        SWFAddress.addEventListener(SWFAddressEvent.CHANGE, this.handleChange);
    }

    //SWFAddress suppose to call this function
    this.handleChange= function(evt) {
    //some code here
    }

}

//instantiate the SomeClass
var someVar = new SomeClass();
someVar.initializeSWFA();

This line does not work here:

SWFAddress.addEventListener(SWFAddressEvent.CHANGE, this.handleChange);

I tried changing it to:

SWFAddress.addEventListener(SWFAddressEvent.CHANGE, this.handleChange());

or

var self = this;
SWFAddress.addEventListener(SWFAddressEvent.CHANGE, self.handleChange);

and these don't work either.

So how to reference a javascript function from a class in situation like this? If the function handleChange would be outside of the class I can write the function's name.

Thank you in advance

EDIT

First, thank you for all the answers. I am still trying to figure how this all works in Javascript. I am not used to the object oriented model like here in Javascript.

This is the solution for now. I still can't figure out how to do this nicely in Javascript but this solution works. I tried to implement the solution suggested by ehudokai (thank you) however was not able to make it work.

function SomeClass() {
    //this adds the this.handleChange() function to the
    //SWFAddress event listener
    this.initializeSWFA = function() {
        //SWFAddress variable is instantiated in SWFAddress javascript file
        //so I can use it here
        SWFAddress.addEventListener(SWFAddressEvent.CHANGE, someFunc);
    }

    //SWFAddress suppose to call this function
    this.handleChange= function(evt) {
    //some code here
    }

}

//instantiate the SomeClass
var someVar = new SomeClass();

function someFunc(evt) {
    someVar.handleChange(evt);
}

someVar.initializeSWFA();

I don't like this because this involves defining one extra function, so takes extra space If anybody figures out how to add a method to SWFAddress EventListener from a Javascript object, please help me out.

Was it helpful?

Solution

Your class structure is perfectly valid. However, if your handleChange() function uses the this keyword, expecting someVar, then that is where your problem lies.

This is what happens:

  1. SWFAddress.addEventListener(SWFAddressEvent.CHANGE, this.handleChange); correctly references the handler function within the class. SWFAddress caches that function to some variable f until the event is dispatched.
  2. When the event is dispatched, SWFAddress calls f. While the reference to the function is preserved, the reference to the context, or this, is not. Therefore this defaults to window.

To get around this, you simply need to use an anonymous function that captures the variables within the class scope. You can call the handler with the correct context from within this anonymous function:

function SomeClass() {
    this.initializeSWFA = function() {
        // Save a reference to the object here
        var me = this;

        // Wrap handler in anonymous function
        SWFAddress.addEventListener(SWFAddressEvent.CHANGE, function (evt) {
            me.handleChange(evt);
        });
    }

    //SWFAddress suppose to call this function
    this.handleChange= function(evt) {
    //some code here
    }

}

An explanation of this, as requested by the OP:

The this keyword can be explained in different ways: take a read of firstly this article about scope, and then this article about object-oriented javascript.

I'd like to throw in my quick reasoning too, which you may find helpful. Remember that Javascript doesn't have "classes" as languages such as Java do. In those languages, a "method" of a class belongs only to that class (or could be inherited). In javascript however, there are only objects, and object properties, which can happen to functions. These functions are free agents -- they don't belong to one object or another, just like strings or numbers. For example:

var a = {
    myMethod: function () {...}
};

var b = {};
b.myMethod = a.myMethod;

In this case, which object does myMethod belong to? There is no answer, it could be either a or b. Therefore a.myMethod is simply a reference to a function, disassociated from the "context", or parent object. Therefore this has no meaning unless it is called explicitly using a.myMethod() or b.myMethod(), and thus defaults to window when called in any other way. It is for the same reason that there is no such thing as a parent or super keyword in javascript.

OTHER TIPS

I'm afraid I can't pinpoint your problem, but I would say that it has something to do with your use of SWFAddress. The way you're structuring SomeClass and it's methods is completely valid, contrary to what some other answers here are stating.

Further clarification to miki's (now deleted) question from another answer, regarding how this works:

There are two cases for how this behaves; regular functions and functions invoked with the new-operator.

For regular function invokations, this refers to the object to the left of the dot (loosely speaking): For example, when writing someVar.initializeSWFA(), this will refer to someVar. When calling a function without the dot, this will refer to the global object. A function can be assigned from one object to another and hence this will be shifted, like this:

var someVar = new SomeClass();
var anotherVar = {};
anotherVar.aNewNameForTheSameFunction = someVar.initializeSWFA;
anotherVar.aNewNameForTheSameFunction(); // inside of this call to initializeSWFA, "this" will be "anotherVar"

Then we also have the case when invoked with the new-operator. In that case, new will create a new object for you and this will refer to that object.

There are also ways to invoke a function with an explicitly set this, by using the call-function:

var someVar = new SomeClass();
var aNumber = 5;
someVar.initializeSWFA.call(aNumber, arg1, arg2, ..., argN);

That will call the function initializeSWFA with aNumber as this and also pass it the parameters arg1, arg2, etc. Note that someVar is taken out of the equation in that case.

I think the best thing to do is to stop thinking of SomeClass as a Class.

Javascript doesn't have classes. It uses prototypical inheritance. Which I won't go too deeply into here. Essentially what it means is you just have objects. And if you want to create another object like the first one, you use the Object.prototype attribute to do that.

So if you want to do what you're trying to. (assuming that SWFAddress works like most javascript), do the following.

var someVar = {  // (using object notation)
    initializeSWFA : function(){
        SWFAddress.addEventListener(SWFAddressEvent.CHANG, this.handleChange);
    },
    handleChange : function(){
        // your code here
    }
}

at this point you can call someVar directly

someVar.initializeSWFA();

If instead you want to create an object that you can inherit other objects from try the following.

var baseObject = function(){};
baseObject.prototype.handleChange = function(){
    // your code here
}
baseObject.prototype.initializeSWFA = function(){
    SWFAddress.addEventListener(SWFAddressEvent.CHANGE, this.handleChange);
}

var someVar = new baseObject();
someVar.initializeSWFA();

the new operator simply creates a new object that inherits the .prototype of the object specified.

Hope that helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top