views:

163

answers:

1

Given the following HTML example...

<div id='div1'>div one</div>
<div id='div2'>div two</div>

...I found that the following jQuery code...

$('#div1').click(function() {

    var $d = $(this);    // Using 'this' instead of '#div1'

    $d.add('#div2').remove();
});

...would not add #div2 to the set referenced by $d, but this code...

$('#div1').click(function() {

    var $d = $('#div1');    // Using '#div1' instead of 'this'

    $d.add('#div2').remove();
});

...successfully added #div2.

Upon consulting firebug, I found that using $(this) gave the jQuery object a context of #div1, but doing $('#div1') gave the object a context of document.

Given this information I tried...

var $d = $(this, document);

...and the add() function worked as expected.

So here's the question. Could someone please explain to my why a different context is assigned when using $(this) vs $('#div1')?

Thanks much!

+6  A: 

Edited to better address your question:
First, look at the relevant code here, this is how jQuery handles the $() call. When you're passing a DOM element (which this is, it's the div itself) the context is the DOM element itself, this better allows handling of document fragments, etc. When you pass a string, the default context is document (because it's the top ancestor to search from). Remember a $(selector, context) is actually calling context.find(selector) under the covers, so it makes sense to start at document if nothing's specified.

Note: you can always check the context, it's an available property, like this: $(this).context

For the .add() behavior:
.add() uses the same context for selecting as the jQuery element you're adding to, so what you're seeing is the expected behavior. For a better description, see how .add() is written:

add: function( selector, context ) {
    var set = typeof selector === "string" ?
                jQuery( selector, context || this.context ) :
                jQuery.makeArray( selector ),
                all = jQuery.merge( this.get(), set );

    return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
            all :
            jQuery.unique( all ) );
    }

Note how it uses the current context if none is passed. To override this though, it accepts a context, to which you can pass document and get the result you want, like this:

$('#div1').click(function() {
   $(this).add('#div2', document).remove();
});
Nick Craver
Thanks for the answer. I think maybe I'm just not understanding the purpose/use of the context of a jQuery object. Why does `$d` have a context of `#div1` in the first place instead of `document`?
patrick dw
@patrick - You can see how `$(this)` is handled here: http://github.com/jquery/jquery/blob/master/src/core.js#L59 When you do `$(DOMElement)` the context is that DOM element, just how it works. For example, you could be dealing with an element that's not in the DOM, in a document fragment for example, so `document` doesn't always work.
Nick Craver
@patrick - I re-read your post and re-wrote most of the answer to better address your main question, hopefully that clarifies it a bit more, let me know if it still leaves questions.
Nick Craver
OK, I think I'm getting it. So the reason jQuery assigns `#div1` is that jQuery doesn't really know what the heck else to put there (without doing a traversal every time, I suppose). So overriding the context in `$d` is safe and irrelevant in terms of expected functionality.
patrick dw
@patrick - Exactly! :)
Nick Craver
@Nick - Excellent. Thanks much!
patrick dw