1

I have 3 queries about selector performance:

First, is there any performance differences in the following statements:

$('#content .someclass') and $('.someclass', '#content')

I have always used the first way but more recently a lot more people seem to be moving to the second option. Is there any benefit between the two

Second, if I added div.someclass, would that be better than just .someclass (if all the elements of someclass are going to be divs anyway). I would have thought the first one in this case would be slower as it has to get all the divs first followed by the ones with .someclass but as I'm not sure how the selectors work I'm only guessing

Finally, if I use $(this), would it be better to cache this object - var $thisobject = $(this) or is there no difference? I always thought $(this) was a jQuery object in it's own right, but I now think that it is actually converting this into a jQuery object so perhaps sticking it into a variable would be better than calling multiple $(this)

3
  • The second is an undocumented usage of the $() method. The context argument must be an element, a jQuery object, or a Document.
    – Kevin B
    Commented Jun 4, 2013 at 15:53
  • Have you tried running any performance tests of your own, like on jsPerf.com?
    – j08691
    Commented Jun 4, 2013 at 15:55
  • no, I didn't know of any performance testers. I'll have a go
    – Pete
    Commented Jun 4, 2013 at 15:56

3 Answers 3

1

There is a third choice in addition to the two you listed:

1: $('#content .someclass')

2: $('.someclass', '#content')

3: $('#content').find('.someclass')

One thing we can definitely say without running any tests is that #3 is faster than #2. That's because #2 turns into #3 internally. Here's the jQuery source code that does this. It's in the init() function which is really the jQuery constructor. After a fairly lengthy series of tests, it detects that you've called $(selector,context) and makes a $(context).find(selector) call instead:

// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
} else {
    return this.constructor( context ).find( selector );
}

You could make that $(context).find(selector) call yourself and avoid the extra checks.

So #2 is never the fastest code; #3 will always beat it.

Also as @KevinB points out, #2 is not a documented use of the $/jQuery function. This may be just an oversight in the docs, since it's a straightforward conversion to #3 which is a documented use of the function, and the code has worked this way for years.

In any case, there is hardly any reason to ever use #2 even in its documented cases, since #3 is both faster and easier to understand.

How does #3 compare with #1? Probably faster in most cases, but it may vary among browsers and among particular selectors and page complexity. jsPerf is your friend here, but be sure to give it a page similar to the one that matters, not just a contrived test.

Same thing for div.someclass vs. .someclass. Test it and see.

Regarding $(this), that $ function name sometimes makes things look like magic when they are just ordinary JavaScript function calls. For purposes of understanding, try using the jQuery function name instead:

jQuery(this)

Now it should be more clear that this is indeed a function call, not some kind of magic syntax. It's the same when you use $(this) or $(anything): it's always a function call. So yes, if you're using it repeatedly, it's a good idea to save the result in a variable:

var $this = $(this);

My only suggestion would be not to name the variable $thisobject. The extra object verbiage doesn't really make the name any more clear; a simple $this will be more familiar to other developers. Or perhaps better to use a more descriptive name, e.g.

var $element = $(this);

In general, this and $this are badly overused in jQuery code and it's better to use ordinary variables with short but descriptive names whenever possible.

Consider this contrived jQuery plugin:

jQuery.fn.log = function() {
    this.each( function() {
        console.log( this );
    });
    return this;
};

In this short function, this changes meaning twice: First it's the jQuery object, and then it's an individual element from that object, and then it's the jQuery object again. No wonder people have trouble with this!

Instead, you can use the named parameters to .each():

$.fn.log = function() {
    this.each( function( i, element ) {
        console.log( element );
    });
    return this;
};

That's much less confusing, and if you need a jQuery object for element in the inner function you can do it the same way you would with this:

var $element = $(element);
0
1

It depends on the exact nature of the selector.

In general it's better to let the browser do all of the heavy lifting since it has native direct access tot he DOM, so you might expect the former to be faster.

AIUI, browsers typically work from "right to left" in the selector, so it would find all elements with class .someclass and then filter the results to those that are descendants of #content.

In this specific case though, the "parent" is identified by ID, so it may be faster to tell the browser to start at that specific element and only consider its descendants.

In other words, "it depends". Try is on a real-life page, or on jsperf.com, and see what happens.

1

something not mentioned yet is that there's going to be a difference between browsers. in browsers that don't support querySelectorAll, strategy changes. for example, if the browser does support that method, then something like $('#id').find(' > li > a') is likely to be very fast... on a browser that does not (legacy IE, most notably), you might be better off with something like $('#id').children('li').children('a').

1
  • I think it is just IE 6, I believe 7 supports querySeletorAll. I know 8 does.
    – Chris Love
    Commented Jun 5, 2013 at 1:11

Not the answer you're looking for? Browse other questions tagged or ask your own question.