8

I got another question regarding jQuery's architecture. $('div') constructs a new jQuery object:

$('div') instanceof jQuery; // true

I'd like to know why it is possible to query it like an array, allthough it isn't an array?

$('div')[0]; // returns the first div in the document as a DOM node.
$.isArray($('div')); // false

I just love this syntax, it looks so clean! I also noticed this returns the DOM nodes as an array:

console.log($('div'));

Can somebody explain me how to implement this behaviour to my own objects?


My own approach was to make an array with some methods like this:

var a = ['a', 'b', 'c'];
a.method = function(){ return 'test'; };
a; // ['a', 'b', 'c']
a[0]; // 'a'
a.method(); // 'test'

However this doesn't seem to be the way jQuery does it as this is actually an array:

$.isArray(a); // true

I'd like to know how jQuery does this to learn and to see if it's a better solution than mine.

js-coder
  • 8,134
  • 9
  • 42
  • 59
  • You can access *any* property using `[ ]` notation. Not just indices. So just like `$('div')[0]`, you can do `$('div')['jquery']`, which will give you the jQuery version number. –  Jan 09 '12 at 18:14
  • @amnotiam I know that. But when I print usual objects in the consoles they don't output an array. – js-coder Jan 09 '12 at 18:14
  • Ah, if you're asking specifically about the console output, then it really is just the console making its best guess as to what you gave it. [jAndy's answer](http://stackoverflow.com/a/8793090/1106925) shows what consoles typically do. –  Jan 09 '12 at 18:16
  • @dotweb jQuery decided to use numbers as the property names of jQuery objects. You can do that yourself: `var obj = { '0': ..., '1': ..., '2': ... }` - same thing... (String representing integers are valid names for properties.) – Šime Vidas Jan 09 '12 at 18:19
  • 2
    Example: `console.log({"2":"foo",splice:function(){},length:2});` is clearly not an Array being logged, but shows up as `[undefined, undefined, "foo"]` –  Jan 09 '12 at 18:19
  • @ŠimeVidas Are you sure? That still prints an object in the console not an array like `$('div')` does. – js-coder Jan 09 '12 at 18:20
  • 1
    possible duplicate of [Array Like Objects in Javascript](http://stackoverflow.com/questions/6599071/array-like-objects-in-javascript) – pimvdb Jan 09 '12 at 18:26

5 Answers5

10

A jQuery object is what we call a Array-like object. That means, it indeed is a "true" object (infact, all "arrays" are objects in ECMAscript), but it owns certain properties which make it look like a "true" array. Those properties are

  • it as a .length property
  • it owns the .splice() method

those two facts are enough that most js engines consoles will interpretate that object as array.

Example:

var myObject = { },
    push = Array.prototype.push;

myObject.aNiceFunction = function() {
    console.log(this);
};

push.call( myObject, document.getElementById('foo') );
push.call( myObject, document.getElementById('bar') );

myObject.splice = Array.prototype.splice;

If we now log our object

console.log( myObject );

we get the typical jQuery'ish result

[div#foo, div#bar]

See that in action

but we are still able to call our method .aNiceFunction() on that object. By pushing new elements with the Array.prototype.push() method onto our object, ECMAscript will automatically index those elements for us. That was short description what happens under the jQuery hood.

One more word about "Arrays" in ECMAscript. There are no real arrays in this language (if we forget about typed arrays for a second). There is only Object. If we have an object that inherits from Array.prototype we would almost call it an array. Everything we would have left to do is, set the .length property to 0.

jAndy
  • 231,737
  • 57
  • 305
  • 359
  • 2
    JS engines don't interpret anything as an array. JS _users_ interpret things as arrays. :) – SLaks Jan 09 '12 at 18:10
  • @SLaks: touchè. What I was meaning there is, how for instance it is "logged out" by the console object. – jAndy Jan 09 '12 at 18:17
  • That's a function of the Firebug's / Chrome's pretty printer (which are JS users), not the JS engine. – SLaks Jan 09 '12 at 18:18
2

jQuery objects are array-like objects.

An array-like object is an ordinary object that has the same properties that an array does.
An array like object has a length property set to a positive integer, and properties named 0, 1, ... length − 1 containing the array objects.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
1

Treating a jQuery object like an array is an application of duck typing. From Wikipedia:

In computer programming with object-oriented programming languages, duck typing is a style of dynamic typing in which an object's current set of methods and properties determines the valid semantics, rather than its inheritance from a particular class or implementation of a specific interface.

In other words, it's not important that the jQuery function actually return an array instance, as long as it provides the necessary properties (e.g. length, numeric indices) and methods to act like an array.

JavaScript has other array-like objects. For example, the arguments object isn't an array, either, but it has properties (like length) that allow you to pretend it is.

Wayne
  • 59,728
  • 15
  • 131
  • 126
0

jQuery objects are "array-like" objects. Consider the code below:

document.forms.length; // returns 1;
document.forms[0]; // returns a form element.
document.forms.join(", "); // throws a type error. this is not an array.
typeof document.forms; // returns "object"

Modifying your code, you could achieve this same affect:

var a = 
{
    0: 'a',
    1: 'b',
    2: 'c',
    length: 3,
    method: function() {
        return "test";
    }
};
doogle
  • 3,376
  • 18
  • 23
  • `console.log(a)` prints the object not the array. So this doesn't seem to be the way jQuery does it. And by the way I'm not a JavaScript beginner, I know how JavaScript objects work. – js-coder Jan 09 '12 at 18:18
0

I am not sure what this "array-like" craziness is from the other answers. There is no standard terminology for "array-like".

The actual difference here is the difference between an actual array, which is a collection of elements versus a linked list which is a collection of references. In reference to the DOM a linked list is properly referred to as a node list. These articlea have more information:

http://www.mindcracker.com/Story/1016/interview-question-difference-between-linked-list-and-array.aspx

http://www.sitepoint.com/a-collection-is-not-an-array/

http://blog.duruk.net/2011/06/19/nodelists-and-arrays-in-javascript/

austincheney
  • 1,097
  • 7
  • 8