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:
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.