Wednesday, February 1, 2012

This pointer and function pointer in javascript

As shown below, Java or c# will pass current "this" pointer from caller to callee implicitly

void caller()
{
callee(); //caller will be invoked on this pointer used to invoke caller
}


In Javascript, when calling callee() inside caller(), if the invoking object is not specified as this.callee(), it does not implicitly pass the current "this" pointer to invoke callee(). And the global Window object will be used as "this" to invoke function callee.

When invoking constructor in javascript, inside the constructor, the "this" pointer is the current class, not the window object.

Another related issue is, in javascript, function defined in one class can be assigned to another object as method, (Note function is a standalone unit of statements and a method is attached to an object and can be referenced by the this keyword), and when invoking the method from another object, its this pointer is the assigned object, and has nothing to do with the class or instance that defines the function.

Sample code:
function bar()
{
alert(this.constructor.name);
}

function somefunc()
{
alert(this.constructor.name);
}

function apple()
{

this.bar = somefunc;
bar(); //call global bar
his.bar(); //call somefunc

this.internalMethod = function() {
alert("internal method this: " + this.constructor.name);
}
}


//to test the above code, calling following method from html page script section
var myApple = new apple();
myApple.internalMethod(); //myApple is this pointer used to invoke the method
var me = myApple.internalMethod;
me(); //window is used as this pointer to invoke the method


Full js file for testing

function Apple() {
try {
alert("constructor: "+ this.constructor.name);
this.color = "red";
this.bar = somefunc;
bar();
this.bar();

this.internalMethod = function() {
alert("internal method this: " + this.constructor.name);
}

this.internalMethod();

this.getInfo();
}
catch (ex) {
alert("exception: " + ex);
}
}

Apple.prototype.getInfo = function() {
alert(this.color + ', type: ' + this.constructor.name);
};

function bar() {

alert("bar method this: "+ this.constructor.name);
}

// anti-pattern! keep reading...
function somefunc() {
this.getInfo();
alert("somefunc this: "+ this.constructor.name);
}

Full html file for testing

var myApple = new Apple();
myApple.internalMethod();
var me = myApple.internalMethod;
me();