Sergio and the sigil

Guided Tour: jQuery - Array wannabes

Posted by Sergio on 2009-12-22
This post is part of a series called the Guided Tours.

In this second installment we are still looking inside the jQuery code. Trust me, even if it's hard to digest, you can still learn enough if you focus on a little bit at a time.

The code we are interested in today is the following.

//from jQuery 1.3.2
get: function( num ) {
	return num === undefined ?

		// Return a 'clean' array
		Array.prototype.slice.call( this ) : 

		// Return just the object
		this[ num ];
},

That's the code for the command jQuery.fn.get(index), which returns the element at the given index or the entire array if the index is omitted.

The JavaScript idiom that is really interesting in this function is that strangely long function call Array.prototype.slice.call( this ).

That line is needed because we need to return an array and, even though they look like one, the jQuery objects aren't arrays. And they aren't alone in that.

If it walks like a duck...

The Array object is one that we can't avoid becoming familiar with in JavaScript. They are everywhere. Data is passed to functions as arrays. Data is returned in arrays. Or are they?

Aside from jQuery objects there are at least two other important occurrences of data structures that are used like arrays but really aren't: the arguments variable and the DOM NodeList collections.

The arguments variable is the list of parameters passed to the current function and the NodeList is what is returned from members of the the DOM API such as document.getElementsByTagName() or element.childNodes. Both of these types have a length property and expose their items with indices, like arguments[1] or elements[0].

But don't let this small coincidence fool you. As soon as you stop paying attention and try to use another array method, like push, shift, join you'll have your dreams shattered and a TypeErrorto handle.

Help me, jQuery

To solve the above problem and return a real array object instead of the jQuery object itself, the code used the technique we highlighted.

Array.prototype.slice.call( this )

The idea is to use the array.slice() instance method to create a new array. The slice method returns a chunk of the array and it takes two optional parameters (the boundaries) that, when omitted, make the function return a copy of the array itself.

I've written about the prototype object