Peeling Away the jQuery Wrapper and Finding an Array

If you haven't poked around under the hood of jQuery, you might not be aware that when you pass the jQuery function an expression or DOM element it places these elements (or, possibly a single element) into an object, and then this object is returned so that it can be chained. Without getting into the details of chaining, the fundamental concept to remember is this:

Most jQuery methods return the jQuery object itself, which allows methods to be chained.

The interesting thing about the jQuery object is that while its datatype is an object, it has array-like characteristics:

  • its property names (the ones that refer to DOM elements, at least) are numeric
  • it has a length property

Have you ever noticed, for example, a snippet of jQuery code that directly accesses a DOM element by using the bracket operator with the jQuery function?

[js]$('div')[0]; // give me the first DOM element that the // jQuery function found [/js]

Now, the jQuery function returns an object, but it looks like we just treated it as an array. It can also be written like this:

[js]$('div').get(0) // do the same, using a jQuery method [/js]

If this is confusing, let's see if we can clear it up with some code. Go to the jQuery.com homepage, open up Firebug using Firefox, and run the following line of code in the console.

[js]$('div').toSource(); // toSource() is a method of all JavaScript objects [/js]

You should be looking at this in the console:

"({length:25, 0:{}, 1:{}, 2:{}, 3:{}, 4:{}, 5:{}, 6:{}, 7:{}, 8:{}, 9:{}, 10:{}, 11:{}, 12:{}, 13:{}, 14:{}, 15:{}, 16:{}, 17:{}, 18:{}, 19:{}, 20:{}, 21:{}, 22:{}, 23:{}, 24:{}, prevObject:{0:{}, length:1}})"

Looky there! The jQuery function is returning an object with a bunch of properties. If we tack on the bracket operator to the jQuery function, which returns an object, we can access the properties of that object because inside the object are properties with a numeric property name. Fascinating isn't it?

I know what you're thinking: this tutorial is about arrays, not objects. Right, so let's get to the array part. Since we now know that the jQuery function returns an object that only masquerades as a JavaScript array the question at hand is how do I get a true JavaScript array from a jQuery wrapper object. This is actually very simple. Most of you might not have been aware (if not, I showed you earlier) that $('div')[0] and $('div').get(0) return a reference to the first element in the jQuery wrapper object. But, the get() method actually has another purpose. It can quickly turn the DOM elements found in the jQuery wrapper into an array of DOM elements.

Let's return to jQuery.com and open up Firebug again. Inside the console run the following line of code.

[js]$('div').get().toSource(); [/js]

You should now be looking at this in the firebug console:

"[{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}]"

Essentially the .get() method placed all of the DOM elements inside the jQuery wrapper into an array and returned that array. So now you can use default array methods on your array of elements. For example:

[js]$('div').get().toString; //returns the array as a string //this is a method of the array object [/js]

Additionally, since we now have an array we can write a statement like this:

[js]$('div').get()[0].id; //returns the first div's id attribute value [/js]

There is something worth noting here that might not be obvious to those starting out with jQuery or JavaScript. Since we are now returning an array, the chain is broken. You can't chain any jQuery methods after using the .get() method.

But, heck, you have an array. Now you can use the utility functions that jQuery provides ($.each(), $.grep(), $.map(), $.inArray(), $.unique()), as well as core JavaScript methods and properties, to work on the array. I'm not going to demonstrate all of the jQuery utility functions that can be used on an array, but I do want to examine one of them here in this tutorial.

The $.each() utility function, not to be confused with the $('selector').each() method used to operate on a set of DOM elements in a jQuery wrapper, can be used to seamlessly iterate over an array or object. For example, let's say that you would like to store (or cache) a set of <li> elements in an array, because maybe you are going to remove them from the DOM temporarily but eventually will be placing them back on the page. To do this you could use the $.each() utility function to loop over an array and append each <li> element back to the page. In the code example below this is done on page load by converting and storing the jQuery wrapper of <li> elements to an array, and then looping over this array in order to place them back on the page.

[js]
  • task 1
  • task 2
  • task 3
  • task 4
  • task 5
  • task 6
  • task 7
  • task 8
[/js]

Notice that I am forgoing the use of the .ready() event by simply placing my jQuery code before the closing body element.

So, hopefully it's obvious how extremely handy it can be at times to make an array out of a jQuery wrapper. In fact, once you are dealing with an array, you can use a handy plugin called Rich Array. This plugin provides the following additional utility functions for arrays. And yes, there is a bit of duplication here with some of the core utility functions.

$.richArray.in() //Checks whether an array contains some value
$.richArray.unique() //Produces the duplicate-free version of the array
$.richArray.diff() //Finds the difference between two arrays.
$.richArray.intersect() //Finds the intersection of two arrays
$.richArray.filter() //Applies filter to the array, using callback function
$.richArray.map() //Applies callback function for each element in the input array, and returns array of values that this function returned
$.richArray.sum() //Computes the sum of all array elements
$.richArray.product() //Calculates the production of all elements of the array
$.richArray.reduce() //Reduces the array. One-element arrays are turned into their unique element
$.richArray.compact() //Creates new version of array without null/undefined values
$.richArray.without() //Creates a new version of the array that doesn't contain the specified value