What is "this"... callbacks and arguments in JavaScript

JavaScript has this peculiar thing called "this". Beginners like me spend lot of time debugging code because somewhere in some distant corner of the code, a function is having an alien "this".

Inside the method of a class, "this" refers to the object on which the method has been called, thus (sounds like past participle of "this", doesn't it?) allowing us to access the members of the object. So far so good, but things start getting weird (at least for the first time) when we want to use methods of objects as callback functions for some events.

For example, as the following code illustrates, I want to be notified of the area of a certain rectangle (say "rect") whenever a button is clicked. The catch is that attaching the function "rect.getArea" to the "click" event of button is not sufficient! When the callback function is called, inside the callback function, "this" refers to the html DOM object corresponding to the button and not the good old "rect" as our poor unsuspecting newcomer would have thought...
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
function Rectangle (width, height) 
{
    // Yeah! classes in javascript are functions.
    this.width = width;
    this.height = height;
}

Rectangle.prototype.getArea = function ()
{
    // Let's see what "this" is...
    alert (this);

    // if "this" is not a rectangle, the 
    // following line _might_ throw error.
    // because this.width and this.height
    //  _might_ be undefined.
    alert (this.width * this.height);
};

var rect = new Rectangle (9, 11);
var btn1 = document.getElementById ("button1");
var btn2 = document.getElementById ("button2");

// Click the button and check out what "this" is...
btn1.addEventListener ("click", rect.getArea, false);

function bindHandler (handler, object_passed)
{
    // returns the function handler, in such
    // a way that, inside handler, 
    // "this" refers to object_passed.

    function bindedHandler ()
    {
        // arguments is the list of arguments the
        // callback function has got.
        handler.apply (object_passed, arguments);
    }
    return bindedHandler;
}

// Now, we have got what we wanted!
btn2.addEventListener ("click", bindHandler (rect.getArea, rect), false);
Click on the following buttons and see what happens!

But worry not, with a simple 4 line code, things can be made to work the way we want them to work. As can be seen from the above code, the "apply" comes to our rescue. "apply" and "call" are two useful methods one should know exist ;)
  1. Link to apply documentation
  2. Link to call documentation

No comments :

Post a Comment

Note: Only a member of this blog may post a comment.