Object-Oriented Javascript borrow context for event handling

By | March 18, 2011

In object oriented Javascript programing, I used the following method to create “class”(in fact, there’s no class concept in Javascript):

var MyObj = function(){
};

MyObj.prototype={
    aaa : function(){
    }
    ,
    bbb : function(){
    }
    ,
    ccc : function(){
    }
};

Now I want to implement:

Click an element in the page, call the aaa method in MyObj instance, then in aaa method, call ccc method. Attach event to the element in bbb method.

So I can write like this:

<div id="someA">Click Me</div>
<script>
var MyObj = function(){
};

MyObj.addEvent = function(oTarget, sEventType, fnHandler) {
    if (oTarget.addEventListener) {
        oTarget.addEventListener(sEventType, fnHandler, false);
    } else if (oTarget.attachEvent) {
        oTarget.attachEvent("on" + sEventType, fnHandler);
    } else {
        oTarget["on" + sEventType] = fnHandler;
    }
};


MyObj.prototype={
    aaa : function(event){
        alert(event);
        this.ccc();
    }
    ,
    bbb : function(){
        MyObj.addEvent( document.getElementById("someA"), "click", this.aaa );
    }
    ,
    ccc : function(){
        alert("in ccc;");
    }
};

var o = new MyObj();
o.bbb();

</script>

In aaa method, we get the event, but wait, this.ccc(); raises error: this.ccc is not a function

What’s the problem?

Because, when the click event fires on the element, the aaa method is executed but the context/scope is not in the instance of MyObj, in another word, this is the div element.

The solution:

In this situation, we can use the call method of Function to borrow the context from the MyObj instance, so that the this.ccc() method is available in aaa method at execution time. First let’s see the definition of call method(from http://www.javascriptkit.com/jsref/function.shtml):

Lets you call a function (funcA) as if it’s a method of another function (funcB). Specifically, the "this" keyword when used inside funcA now returns funcB. The two methods apply() and call() are useful when you wish an object to "borrow" a method from another object and use it within its own context.

Then we write a help method:

MyObj.BindAsEventListener = function(object, fun) {
    return function(event) {
        return fun.call(object, (event || window.event));
    }
};

At last, we modify the code to make it work:

<div id="someA">Click Me</div>
<script>
var MyObj = function(){
    //borrow the context from MyObj instance to _aaa method
    //so that when _aaa is being executed, this keyword is combined to the instance of MyObj
    this._aaa = MyObj.BindAsEventListener( this, this.aaa );
};

//add event helper method
MyObj.addEvent = function(oTarget, sEventType, fnHandler) {
    if (oTarget.addEventListener) {
        oTarget.addEventListener(sEventType, fnHandler, false);
    } else if (oTarget.attachEvent) {
        oTarget.attachEvent("on" + sEventType, fnHandler);
    } else {
        oTarget["on" + sEventType] = fnHandler;
    }
};

//use call to borrow context
MyObj.BindAsEventListener = function(object, fun) {
    return function(event) {
        return fun.call(object, (event || window.event));
    }
};

//the MyObj "class"
MyObj.prototype={
    aaa : function(event){
        alert(event);
        this.ccc();
    }
    ,
    bbb : function(){
        MyObj.addEvent( document.getElementById("someA"), "click", this._aaa );
    }
    ,
    ccc : function(){
        alert("in ccc;");
    }
};

var o = new MyObj();
o.bbb();

</script>

Please refer the comments in the code, that’s it. Smile

You can also download a executable sample.