jQuery: debugging the this keyword in object-oriented programming

jQuery: debugging the this keyword in object-oriented programming

Understanding the relationship between the this keyword and scope when using objects with jQuery.

The JavaScript keyword this is said to mysteriously disappear by many jQuery developers. There's no magic here. Simply put, this works together with the scope created by JavaScript functions and objects. But why does it disappear and where is it gone when it disappears? Actually, this doesn't disappear but simply goes out of scope. In other words, the JavaScript interpreter often assigns its value to a new scope so that this now points to this new scope. In this article we'll see a practical example involving jQuery and JavaScript objects.

Let's create a simple object:

var App = new function() {

	// code here

}();

Now we can create a property that stores a reference to an HTML element:

this.element = $('#test');

Here this points to App and you can access your element as App.element from the outside of the object. So far so good. Let's try to add a method that retrieves the ID of the HTML element:

this.get = function() {
   return '#' + this.element[0].id;
}

At this point, our this keyword still maintains a link to the App object so that you can normally access the element property. Nothing strange or unusual so far.

Things get more complicated when we add extra scopes to our object, for example by adding a jQuery event:

this.action = function() {
  this.element.click(function() { // New scope !!!
      alert(this.get()); // Now this points to App.element, not to App
  });
};

Our click event has created a closure. Then the this keyword now points to the current HTML element, not to App. Calling this method results in a JavaScript error:

Uncaught TypeError: Object #<HTMLDivElement> has no method 'get'

Fortunately, a simple solution to this problem is to store the this keyword in a variable before creating methods and properties. By doing so, we make sure that will always have a safe reference to our main object:

var App = new function() {

	var self = this; // store this that points to App
	
	// methods and properties

}();

Now we can access our methods and properties even if the main scope has changed. An example:

this.fix = function() {

   this.element.animate({
      fontSize: '20px'
   }, 800, function() { // New scope !!!
      alert(self.get()); // self points to App, so that get() can be accessed
      $(self).bind('clear', function() { // bind a custom event to App
            self.element.animate({ // self = App
                fontSize: '16px'
            }, 800);
       });

       $(self).trigger('clear'); // trigger the custom event
   });
}

You can see a test here.