3

I have just seen a google tech talk presented by John Resig where he said jQuery operates as an array. Following that advice I have been playing with a subclassed array and it works great but I have been looking through the jQuery source and can't see that they have used the same method of

jQuery.prototype = new Array();

And I can't see it even taking the native Array.prototype.methods with call/apply or in the prototype chain in the window.$ object, so I am wondering how does the jQuery object return an array of the selected elements.

I have tried using an ordinary object, but if returning an array it stops the ability to chain commands

If it is possible to take some methods from Array.prototype what is essential to return an array?

This is what I was playing with.

;(function(window, document, undefined){

    function MyLib(){};

    // prototype constructor functions
    function Core(){};
    function Methods(){};

    // create new instance of the MyLib object and call the construct method
    function myLib(selector){
        return new MyLib().construct(selector);
    }
    // allow adding new methods to the prototype from the window. 
    // eg $.extend('module', 'name', 'function')
    myLib.extend = function(module, name, fn){
        if(typeof fn === 'function'){
            if(!MyLib.prototype[module][name]){
                MyLib.prototype[module][name] = fn;
            }
        } else if(typeof fn === 'object'){
            for(var key in fn){
                if(!MyLib.prototype[module][key]){
                    MyLib.prototype[module][key] = fn[key];
                }
            }
        } else {
            throw new Error("invalid type, function or objects are required");
        }
    }

    MyLib.prototype = new Array();
    MyLib.prototype.core = new Core();
    MyLib.prototype.methods = new Methods();

    MyLib.prototype.construct = function(selector){
            var elems = document.getElementsByTagName(selector);
            Array.prototype.push.apply(this, Array.prototype.slice.call(elems, 0, elems.length));
            return this;
        };

    // access to prototype objects with $.core && $.methods
    myLib.core = MyLib.prototype.core;
    myLib.methods = MyLib.prototype.methods;

    // give the window access to the constructor function
    window.$ = myLib;
    // give the window access to the prototype object for debugging
    window.$$ = MyLib;

})(window, document);

// this adds a new method to the methods object within the prototype
$.extend('methods', 'test', function(){alert('method successfully added')});

// the added method can be accessed with
$.methods.test();
// or
$('tagName').test();

thanks for any answers

synthet1c
  • 6,152
  • 2
  • 24
  • 39
  • 1
    That definitely isn't how jQuery does it. jQuery defines specific methods of Array on the jquery prototype, but not all of them. All that's happening in jquery is an object is given a length and array-like properties, and a few Array methods. – Kevin B Feb 11 '14 at 15:37

1 Answers1

4

To work "as an array" (we usually speak of "array-like" object) you don't inherit from Array, you simply have to

  • have a relevant property named length
  • have properties "0", "1"... length-1 (you might skip some)

Example :

var a = {
  length: 2,
  "0": 'first',
  "1": 'second'
}
var b = [].slice.call(a); // yes, Array functions work !
console.log(b); // logs ["first", "second"] 

Of course you can make all this easier for the lib users by defining a prototype based class and the relevant prototype functions (just as jQuery does) :

var A = function(){
  this.length = 2;
  this['0'] = 'first';
  this['1'] = 'second';
}
A.prototype.slice = [].slice;
A.prototype.splice = [].splice;
var a = new A, b = a.slice();
console.log(a); // logs ["first", "second"] because of the splice function
console.log(Array.isArray(a));
console.log(b); // logs ["first", "second"] because it's really an array
console.log(Array.isArray(b)); // true

If you want your objects to be logged as arrays, you need to have the splice function.

Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
  • I did set up one that did that, but it didn't return an array object, it always returned the last element of the array-like object. – synthet1c Feb 11 '14 at 15:37
  • 2
    @synthet1c I don't understand your comment. – Denys Séguret Feb 11 '14 at 15:40
  • I used a constructor function that specified the length property when the construct method was called. Because I was returning this it was returning the array-like object, but it was only showing the last element in it when it returned. It's not a huge deal as what I am using is working, and was working when I used an Array-like object, I was just wondering why jquery returns an array to the console – synthet1c Feb 11 '14 at 15:56
  • 2
    @synthet1c To have your objects logged as arrays, you need to have the `splice` function – Denys Séguret Feb 11 '14 at 15:58
  • I found the issue, it was returning the last elem when I called the native push method, so I will just have write a method to add to the object. thanks for your help dystroy. – synthet1c Feb 11 '14 at 16:15