Slippery When Wet #4: this is it – the this keyword in Javascript

I proudly present to you the fourth in a infinite number of posts of “Slippery When Wet.” In these posts I show you a little bastard I stumbled on.

Coming from the C++/C#/Java world, the ‚this‘ keyword is well known for accessing the instance of the class itself. For accessing members, it is not mandantory but often favored for clearness.

With this background, a first try could look like this (complete html page in the package, file this1.html):

var marc = {
    name: "Marc",
    hello: function(visitor) {
        document.write("Hello " + visitor + ", my name is " + name + "!")
    }  
}

window.onload = function()
{
    marc.hello("Peter");
}

And the output is:

Hello Peter, my name is !

OK, let’s try again!
We call the name property explicit (this2.html):

        document.write("Hello " + visitor + ", my name is " + this.name + "!")

And the output is, as expected:

Hello Peter, my name is Marc!

So, it’s a piece of cake, we have only to put the this keyword for all members, and we’re done…

Wait, not so fast, youngster!

Let’s try it with a function reference like in the next example (this3.html):

var marc = {
    name: "Marc",
    hello: function(visitor) {
        document.write("Hello " + visitor + ", my name is " + this.name + "!")
    }  
}

var greet = marc.hello;

window.onload = function()
{
    greet("Peter");
}

And the output is:

Hello Peter, my name is !

The name is lost again!

This problem occurs because JavaScript doesn’t support implicit binding in a way C++ and others do.

With calling the function through the function reference, the this inside the hello function points not to marc but to the window. To verify this thesis, we just add a name to the window:

var marc = {
    name: "Marc",
    hello: function(visitor) {
        document.write("Hello " + visitor + ", my name is " + this.name + "!")
    }  
}

var greet = marc.hello;

window.name = "Sue";

window.onload = function()
{
    greet("Peter");
}

And the output is:

Hello Peter, my name is Sue!

But how can we solve this problem? The two easiest solutions are apply and call:

var marc = {
    name: "Marc",
    hello: function(visitor) {
        document.write("Hello " + visitor + ", my name is " + this.name + "!")
    }  
}

var greet = marc.hello;

window.onload = function()
{
    greet.apply(marc, ["Peter"]);
    document.write("<br />");
    greet.call(marc, "Peter");
}

And the output is:

Hello Peter, my name is Marc!
Hello Peter, my name is Marc!

With apply and call, you do an explicit binding. The object you pass as the first argument (in our example marc) does not need to have the function itself, but should of course have the members that are used inside the function.
The difference of apply and call is only in the signature of the function. With apply, the parameter have to be passed inside an array. With call, the parameters are lined up after the explicit binding object.

This should give you some ideas to identify problems coming from the binding and some solutions to solve them.

For further reading i suggest the following articles:

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.