Uncovering jQuery's Hidden Features

jQuery is not always as it appears. There's a lot of cool stuff going on under the surface, and there are many methods just waiting to be discovered, and many potential usages of jQuery's API that you may not have considered before. In this article I'll be taking you through a few of the not-so-obvious things I've discovered about jQuery.

Under its skin, the jQuery function (commonly referred to as the "wrapper" function) simply returns an instantiated jQuery object -- i.e. an instance of the 'jQuery.fn.init' constructor.

This is useful to know; with this information we know that each time we call 'jQuery' we're actually creating a totally unique object with a set of properties. jQuery is clever in that it gives you an object that can be treated as an array. Each of your elements (all together, commonly known as the "collection") is referenced within the object under a numerical index, just like within an array. And jQuery also gives this object a 'length' property, just as you would expect from an array. This opens up a world of possibilities. For one, it means that we can borrow some functionality from 'Array.prototype'. jQuery's 'slice' method is a good example of this -- modified from the source:

The native 'slice' method doesn't care that 'this' is not a real array-- it'll be fine with anything that's got a 'length' property and [0], [1], [2] etc.

There are some other interesting properties within this jQuery object -- '.selector' and '.context' will, most of the time, reflect the arguments that you pass into 'jQuery(...)'.

var jqObject = jQuery('a');
jqObject.selector; // => "a"

One thing that's important to note is that jQuery will sometimes give you new jQuery objects to work with. If you run a method that changes the collection in some way, such as '.parents()', then jQuery won't modify the current object; it'll simply pass you a brand new one:

As of 1.4 you can pass a second argument to the jQuery function when you're creating an element -- the object you pass will, for the most part, act as if you were passing it to '.attr(...)'. However, jQuery will map some of the properties to its own methods, for example, the 'click' property maps to jQuery's 'click' method (which binds an event handler for the 'click' event) and 'css' maps to jQuery's 'css' method etc.

To check out what properties map to jQuery's methods, open your console and type 'jQuery.attrFn'.

3. Serialize your Inputs

jQuery provides a method that you can use to serialize all of the inputs within one or more forms. This is useful when submitting data via XHR ("Ajax"). It's been in jQuery for a long time but it's not often talked about and so many developers don't realise it's there. Submitting an entire form via Ajax, using jQuery, couldn't be simpler:

jQuery also provides the 'serializeArray' method, which is designed to be used with multiple forms, and the 'param' helper function (under the jQuery namespace) which takes a regular object and returns a query string, e.g.

4. Animate Anything

jQuery's 'animate' method is probably the most flexible of jQuery's methods. It can be used to animate pretty much anything, not just CSS properties, and not just DOM elements. This is how you would normally use 'animate':

jQuery('#box').animate({
left: 300,
top: 300
});

When you specify a property to animate (e.g. 'top') jQuery checks to see if you're animating something with a style property ('element.style'), and it checks if the specified property ('top') is defined under 'style' -- if it's not then jQuery simply updates 'top' on the element itself. Here's an example:

jQuery('#box').animate({
top: 123,
foo: 456
});

'top' is a valid CSS property, so jQuery will update 'element.style.top', but 'foo' is not a valid CSS property, so jQuery will simply update 'element.foo'.

We can use this to our advantage. Let's say, for example, that you want to animate a square on a canvas. First let's define a simple constructor and a 'draw' method that'll be called on every step of the animation:

Quickly hovering over a bunch of anchors and then hovering over them again will cause the animations to queue up and occur one at a time -- I'm sure many of you have witnessed this queuing effect before. If not, check it out here: http://jsbin.com/aqaku

The 'queue' method is similar to the well-known 'each' method in how it's called. You pass a function, which will eventually be called for each of the elements in the collection:

Passing just a function to 'queue' will cause that function to be added to the default 'fx' queue, i.e. the queue used by all animations done by jQuery. Therefore, this function will not be called until all current animations occurring on each element in the collection (in this case, all anchors) have completed.

Notice that we're adding a class of 'all-done' in the function above. As outlined, this class will only be added when all current animations are complete. We're also calling the 'dequeue' method. This is very important, as it will allow jQuery to continue with the queue (i.e. it lets jQuery know that you're finished with whatever you're doing). jQuery 1.4 provides another way of continuing the queue; instead of calling 'dequeue', simply call the first argument passed to your function:

This does exactly the same, although it's slightly more useful in that it can be called anywhere within your function, even within a mess of closures (that typically destroy the 'this' keyword). Of course, pre-jQuery-1.4 you could just save a reference to 'this', but that would get a bit tiresome.

To add a function to a custom queue, simply pass your custom queue's name as the first argument and the function as the second:

7. Event Namespacing

jQuery provides a way for you to namespace events, which can be very useful when authoring plugins and third-party components. If needed, the user of your plugin can effectively disable your plugin by unbinding all event handlers that it's registered.

To add a namespace when registering an event handler, simply suffix the event name with a period and then your unique namespace (e.g. '.fooPlugin'):

I'm a freelance web developer based in Hampton, UK. I write about and enjoy front-end web development. Most of what I write focuses on my favorite topic, JavaScript! To read my blog or find out more about me please visit my site!