Understanding How The jQuery Constructor Creates Lots of Extra jQuery Objects
The jQuery constructor, which is what creates the jQuery objects we're used to working with, creates lots of extra throw away jQuery objects. For anyone concerned with performance it's useful to know what's going on so we can take advantage of any performance optimizations. Let me show you what I mean with a simple example. In both jQuery 1.4.4 (used in Drupal and still popular) and jQuery 1.8.1 (the latest release as of this writing) the following example creates 3 jQuery objects. One of these is returned to be used in chaining or other code.
$('#foo', document);
If you iterate over a set of 100 items and create a new jQuery object from each of these you end up creating 300 jQuery objects with this method. Let's take a look at what's happening.
Note: If your jQuery is in noConflict mode you will need to use jQuery instead of the alias $.
The Constructor: jQuery and jQuery.fn.init
The source code to look at is for the call jQuery which creates a new object using jQuery.fn.init. In 1.8.1 it looks like (the difference to 1.4.4 is rootjQuery):
jQuery = function( selector, context ) { // The jQuery object is actually just the init constructor 'enhanced' return new jQuery.fn.init( selector, context, rootjQuery );}
jQuery.fn.init
is a function that deals with all kinds of special cases that might get passed into the jQuery constructor. Knowing how these special cases work can help us create fewer jQuery objects making our JavaScript perform faster.
The Standard Case
Most of the time if you use jQuery the right way you'll end up creating two objects every time you construct something new with jQuery. One of them is thrown away and eventually caught by garbage collection. But, it's good to know about these throw away objects because they do take time and resources for a JavaScript engine to handle.
jQuery('#foo')
Creating a new jQuery object only using a single id creates just one jQuery object. This is a special case jQuery has been optimized for. This is different from the case jQuery('#foo', document)
which creates 2 jQuery objects. The case where there is only the id assumes document
is the context (for in browser uses).
jQuery(context).find('.bar')
If you have a case where you looking for a selector on something other than document
than you can create one less object by using jQuery(context).find('.bar')
than jQuery('.bar', context)
. The reason for this is quite simple. When you call jQuery('.bar', context)
the special case is to do jQuery(context).find('.bar')
. In addition to one fewer object you also avoid some internal jQuery logic.
Even if you are searching on document
and you pass that in as the second parameter you should use the optimization here. $('.bar', document)
creates 3 jQuery objects and this optimization works to speed it up and create one less object.
Element names and 1.4.4
In jQuery 1.4.4 there is an optimization no longer in the latest jQuery release. If you make a call like $('div')
, where you are searching by the name of an element type, it creates just one jQuery object. This is a special case. In jQuery 1.8.1 two objects are created like almost all cases in jQuery.
Understanding vs. Writing Good Code
Understanding the jQuery constructor and writing elegant high performance code are two different things. If you want to write high performance jQuery it's useful to know much more of the jQuery source than this, how to take advantage of it, and to know plain JavaScript which, being native code, is faster than user space code.
For anyone who wants to really understand jQuery I recommend reading the source.