Does jQuery do any kind of caching of "selectors"?

Viewed 22940

For example, will the first piece of code perform a full search twice, or is it smart enough to cache results if no DOM changes have occurred?

if ($("#navbar .heading").text() > "") {
  $("#navbar .heading").hide();
}

and

var $heading = $("#navbar .heading");

if ($heading.text() > "") {
  $heading.hide();
}

If the selector is more complex I can imagine it's a non-trivial hit.

14 Answers

Always cache your selections!

It is wasteful to constantly call $( selector ) over and over again with the same selector.

Or almost always... You should generally keep a cached copy of the jQuery object in a local variable, unless you expect it to have changed or you only need it once.

var element = $("#someid");

element.click( function() {

  // no need to re-select #someid since we cached it
  element.hide(); 
});

jQuery doesn't, but there's the possibility of assigning to variables within your expression and then use re-using those in subsequent expressions. So, cache-ifying your example ...

if ((cached = $("#navbar .heading")).text() > "") {
  cached.hide();
}

Downside is it makes the code a bit fuglier and difficult to grok.

It's not so much a matter of 'does it?', but 'can it?', and no, it can't - you may have added additional matching elements to the DOM since the query was last run. This would make the cached result stale, and jQuery would have no (sensible) way to tell other than running the query again.

For example:

$('#someid .someclass').show();
$('#someid').append('<div class="someclass">New!</div>');
$('#someid .someclass').hide();

In this example, the newly added element would not be hidden if there was any caching of the query - it would hide only the elements that were revealed earlier.

I don't think it does (although I don't feel like reading through three and a half thousand lines of JavaScript at the moment to find out for sure).

However, what you're doing does not need multiple selectors - this should work:

$("#navbar .heading:not(:empty)").hide();
Related