What is this?

read 15 comments

One of the most confusing aspects of jQuery is how it assigns scope during callbacks. It must be confusing because the topic generates a lot of questions on the mailing list. It's too bad, really, because jQuery sets the scope in order to simplify your code, not make it more confusing.

So here are some pointers that may help you remember what this is.

this is a DOM element

When is this a DOM element? The short answer is - usually. Scripting with jQuery quite often involves the use of callback functions. Whether handling an event, iterating a collection of nodes, animating an image, or applying a dynamic filter, callbacks are used to invoke your custom code at the appropriate time. To make things easy for you, jQuery sets the scope of the callback function to the element which is the subject of the callback. For example, when we want to handle a mouse click event for an element we bind a handler function to the event like so:

JavaScript:
  1. $('#myButton').bind('click', function() {
  2.     // our code to handle the click event goes
  3.     // here, in the callback function
  4. });

When a user clicks the 'myButton' element, jQuery invokes the callback function that was passed to the bind method. But when it invokes our callback it sets the current scope to the DOM element that initiated the event, in this case the 'myButton' element. jQuery does this as a convenience. The object you are most likely to need in the event callback is the element that triggered the event. And what easier way to have access to it than by using the this keyword? So within the callback function it can be assumed that this is the relevant DOM element:

JavaScript:
  1. $('#myButton').bind('click', function() {
  2.     // 'this' is the DOM element that triggered the event
  3.     alert(this.id == 'myButton');
  4. });

Let's look at how often this is a DOM element when using jQuery. We just saw the case of an event handler; here are a few more:

Iterating elements with the each method:

JavaScript:
  1. $('div').each(function() {
  2.     // 'this' is a DOM element
  3.     alert(this.tagName.toLowerCase() == 'div');
  4. });

Using the load AJAX method:

JavaScript:
  1. $('#myDiv').load('myUrl.php', function() {
  2.     // this is the DOM element
  3.     alert(this.id == 'myDiv');
  4. });

Using animation:

JavaScript:
  1. $('#myDiv').fadeOut('slow', function() {
  2.     // this is the DOM element
  3.     alert(this.id == 'myDiv');
  4. });

Using selection filters:

JavaScript:
  1. var set = $('div').filter(function() {
  2.     // this is the DOM element
  3.     alert(this.tagName.toLowerCase() == 'div');
  4.     return true;
  5. });

Using the "document ready" construct:

JavaScript:
  1. $(document).ready(function() {
  2.     // 'this' is the document object
  3.     alert(this === document);
  4. });

Using global AJAX events:

JavaScript:
  1. $().ajaxStart(function() {
  2.     // 'this' is the document object
  3.     alert(this === document);
  4. });

This last one may confuse you. Why is this the document object in the ajaxStart callback? The methods that wire your callbacks to the global AJAX events are binding methods. They bind your event handler to a DOM element. When the event occurs, your handler is called within the context of the DOM element(s). And when you use the dollar function with no arguments jQuery implicitly uses the document object as the selected element. So another way of writing the previous code snippet is:

JavaScript:
  1. $(document).bind('ajaxStart', function() {
  2.     alert(this == document);
  3. });

Now you can probably see how this is determined by how you call the AJAX binding methods:

JavaScript:
  1. $(window).ajaxStart(function() {
  2.     alert(this == window);
  3. });
  4. $('#busyIndicator').ajaxStop(function() {
  5.     alert(this.id == 'busyIndicator');
  6. });
  7. $('div.error').ajaxError(function() {
  8.     alert(this.tagName.toLowerCase() == 'div');
  9. });

this is an Object

I mentioned earlier that when iterating elements with jQuery's each iterator, this is always a DOM element. Technically, it is more accurate to say that within an each iteration, this is the subject of the current iteration loop. This distinction is important because jQuery's each method can be used to iterate over any array-like object, not just nodeLists.

JavaScript:
  1. var arr = ['a','b','c'];
  2. $.each(arr, function(index, obj) {
  3.     // 'this' is the object of the current iteration
  4.     alert(this.constructor == String);
  5.     alert(arr[index] == this);
  6.     alert(this == obj);
  7. });
  8. // or using a different but functionally equivalent syntax:
  9. $(arr).each(function(index, obj) {
  10.     // 'this' is the object of the current iteration
  11.     alert(this.constructor == String);
  12.     alert(arr[index] == this);
  13.     alert(this == obj);
  14. });

this is a jQuery Object

Plugin authors take note! If you've authored a plugin whose functionality can be applied to many elements, then you've most likely done so using the standard fn extension:

JavaScript:
  1. $.fn.myPlugin = function() {
  2.     // your plugin code goes here!
  3. });

Within your plugin function this is the jQuery object. And if you respect the Plugin Authoring Guidelines, your plugin method will always return this in order to maintain Chainability.

JavaScript:
  1. $.fn.myPlugin = function() {
  2.     // this is the jQuery object
  3.     alert("jQuery version: " + this.jquery);
  4.     return this;
  5. });

Typically, a plugin will operate on every DOM element that has been selected by the jQuery object. In a nutshell, this means using the each method within your plugin. You'll often find this technique implemented as follows:

JavaScript:
  1. $.fn.myPlugin = function() {
  2.     // this is the jQuery object
  3.     alert("jQuery version: " + this.jquery);
  4.     return this.each(function() {
  5.         // this is now the DOM element that is
  6.         // the subject of the 'each' iteration
  7.         alert("current element: " + this.tagName);
  8.     });
  9. });

this is an AJAX settings Object

I talked earlier about about jQuery's load method and the global AJAX callbacks. Those callbacks are specifically bound to a DOM element or set of elements. The rest of the AJAX methods, $.get, $.post,$.ajax, etc, operate outside the context of a specific element set. But these methods can all be passed callback functions so it's important to understandwhat this is in those callbacks. Fortunately, all you need to remember is that for each of the local AJAX callback functions, beforeSend, success, complete, and error, this is always equal to the settings object used for the AJAX call.

JavaScript:
  1. $.get('myUrl', function() {
  2.     // 'this' is the AJAX settings object used by the get call
  3.     alert(this.url == 'myUrl');
  4. });
  5.     type:   'POST',
  6.     url:    'myUrl',
  7.     timeout: 5000,
  8.     beforeSend:  function() {
  9.         alert(this.url == 'myUrl');
  10.     },
  11.     error: function() {
  12.         alert(this.timeout == 5000);
  13.     },
  14.     success:  function() {
  15.         alert(this.type == 'POST');
  16.     },
  17.     complete:  function() {
  18.         alert(this.async == true);
  19.     }
  20. });

Converting this to $this

When this is a DOM element it is often in the context of code that needs to access or manipulate it in some way. This, of course, is something that jQuery excels at. So how do we use the power of the jQuery API when this is a DOM element? Just turn this into $this:

JavaScript:
  1. $('div').each(function() {
  2.     // 'this' is a DOM element
  3.     // wrap 'this' in a jQuery object
  4.     var $this = $(this);
  5.     // now we have the full jQuery API at our disposal
  6.     var title = $this.attr("title");
  7.     if (title != null)
  8.         $this.prepend("
  9. <h2>" + title + "</h2>
  10. <p>");
  11. });

When in Doubt

When you're confused about what this is within a given code block, ask yourself, "What makes the most sense here?" More often than not, the answer to that question is equal to this.

comment feed

15 comments

  1. Excelent, excelent, excelent post. 'This' is great for begginers like me :)
    Thanks!

  2. Aha - that came a fraction too late for me. I ended up writing a blogpost about my discovery of what this means, and where, which I found out the hard way. Still, this article looks great too - thanks for being so comprehensive.

  3. Bill Warters

    Hi there. I got interested in trying out jQuery after seeing your session at the Grandrapids BarCamp. Right now, however, I'm stumped trying to get my selectors straight...I guess this is just not what it seems.

    Briefly, I've got a blog setup I'm building that I'd like to add an "Add to favorites" feature to. I can submit the query and get back the data string I'm looking for, but I can't figure out how to select the span that my trigger link resides within so that I can replace it's html with the returned data.

    Sample blog html snippet

    <h2>A Sample Posting to the Blog</h2>
    <p class="postedby">Posted by <a href="/forums/member/1/">Fred</a> on Aug 03, 2007  
    <span class="favorites_span" id="favorite_1750">
    <a class="Favorites_Trigger" id="1750" href="/forms/favorite-add/1750">Add to favorites?</a>
    </span>
    </p>
    <p>Here is a sample posting in the blog. This could be written by an expert in the area.
    </p>

    And here's the bit of Jquery code that I can't quite get to replace my favorites span contents.

    <script type="text/javascript" src="includes/jquery"></script>
    <script type="text/javascript">
    $().ready(function() {
    $('a.Favorites_Trigger') .click (function() {
    var itemid = this.id;
    $.get(this.href, function(data) {
    var myresponse = data;
    var spanid = "favorite_" + itemid;
    alert(data);
    });
    return false;
    });
    });
    </script>

    Should I be trying to get the parent of my trigger link, and if so, how do I get there from "this"?
    As you can see, I can even construct the unique span id I'm looking for based on the link id, but my javascript skills are not up to the task of using this variable correctly in a jquery select statement.
    Any help would be much appreciated...

  4. Bill Warters

    Oops, I thought Karl posted this...I don't recall Mike being at BarCamp GrandRapids.

  5. Bill Warters

    Got it sorted...Here's the selector I needed, placed in the code where the alert now sits.

    $("span#"+spanid+".favorites_span").html(data);

  6. Like Bill, I'm also having trouble combining this and/or $(this) with selectors. A future blog post exploring this topic would be greatly appreciated for us beginners! :-)

  7. Jeroen, $this is just a naming convention used by many jQuery developers. It helps you remember that the variable is a jQuery object rather than a DOM element (assuming you're following the convention). For example:

    $('#myButton').click(function() {
    // in the event handler 'this' is a DOM element
    alert (this.id == 'myButton');

    // wrap this in a jQuery object so we can use the jQuery API
    var $this = $(this);

    // now we have this and $this to play with
    alert( $this.attr('id') == 'myButton');
    });

  8. Tyson

    When you call Jquery from within function in a custom Javascript class, how do you refer to the containing object in the Jquery callback function since Jquery uses "this" to refer to the DOM object in the callback function?

  9. Carter

    Tyson (and anyone else searching this),
    This is how I've been doing it:

    $(".button").bind("click", {that:this}, function(event) {
          var that = event.data.that;
          that.handleEvent();
          return false;
    });

    If you pass in an object after the binding event type arg ("click") it get's tacked onto the event's "data" property. I've been looking for a nicer way to do this... just posted in the google groups forum. Prototype has a bindAsEventListener method that you can tack onto any function to let you say what you want "this" to reference inside the function.

    Hope this helps,
    Carter

  10. @Tyson: You just need to create a closure to capture the object you need to reference in the callback. For example:

    ...
    var self = this;
    $('#myElement').click(function() {
    // here you can use 'self' to reference
    // the enclosing object
    });
    ...

  11. hello , i am trying to use the jQuery load() function , i am using it like this $("#mydiv").load("myfile.php?argument=x");
    all works fine untill i want to process the results returned by the function , meaning that the file myfile.php prints some parts of an form based on some arguments received , the problem is that when i want to process the values of the form elements i cannot because it hasn't generated any html code for them , you can see the problem at http://www.potirnel.8k.ro/formular2/ , any help is great. potirnel@yahoo.com

  12. how do i get the received content of the ajax-/get-function to the div element again ?

    thanks...
    raimund

  13. Brijesh Kumar Sharma

    your live comment preview is meaning less. why are you giving fullish type of live comment.
    when we type then we can see what i type.

  14. Brijesh Kumar Sharma

    what the hell u r doing in coding. how i know that my comment is saved. no any message prompt.

  15. This is sweet and so so helpful.

    Regarding the solution in #10 (which worked perfectly) - is there no other way to bind than this solution? It works but seems inelegant... I wish I could just bind on the function somehow. Ah well! Thanks for this very useful post

One Ping

  1. [...] of the new image to 0 so that we can fade it in using the animate() function. Finally, we attach a callback to remove the z-index classes from the previous image when animate() [...]

Leave a Comment

IMPORTANT:

  • If you wish to post code examples, please wrap them in <code> tags.
  • Multi-line code should be wrapped in <pre><code> </code></pre>
  • Use &lt; instead of < and &gt; instead of > in the examples themselves. Otherwise, you could lose part of the comment when it's submitted.