Search code examples
javascriptjqueryobjectprototypesizzle

How does jQuery clone its methods so quickly?


I am trying to return a query like object, in my first try I try the Object.create method

var ElementArray = {
    someMethod : myMethod,
    ....
}

var addMethods = function(elements) {
    var obj = Object.create(ElementArray);
    obj[0] = elements;
    return obj;
};

var getId = function( query ) {
    return addMethods( doc.getElementById(query) );
};

(jsperf)

I immediately found that this was slower then jQuery(sizzle), especially on firefox. The issues with firefox where probably to do with cross-compartment wrappers (see bug here), but I was still quite dissatisfied.

I also tried using prototype instead

var ElementArray = function(){};
ElementArray.prototype.someMethod = someMethod;
....

var addMethods = function(elements) {
    var obj = new ElementArray();
    ....
};

Slightly better on Chome, but still very slow on firefox.

So my question is, how does jQuery(sizzle), and other libraries do it || Whats the fastest way to return a object with a 1-2 instance properties? (Everything else can just be references)


Solution

  • So my question is, how does jQuery(sizzle), and other libraries do it

    jQuery uses the prototype. It kind of hides that fact by aliasing the prototype to .fn, but it is still the prototype. Here's the jQuery function.

    jQuery = function( selector, context ) {
    
        // The jQuery object is actually just the init constructor 'enhanced'
        // Need init if jQuery is called (just allow error to be thrown if not included)
        return new jQuery.fn.init( selector, context );
    },
    

    And, here's the aliasing:

    jQuery.fn = jQuery.prototype
    

    And, the implementation of the actual jQuery constructor:

    init = jQuery.fn.init = function( selector, context, root ) {
        var match, elem;
    
        // HANDLE: $(""), $(null), $(undefined), $(false)
        if ( !selector ) {
            return this;
        }
    
        // Method init() accepts an alternate rootjQuery
        // so migrate can support jQuery.sub (gh-2101)
        root = root || rootjQuery;
    
       .....
    

    And, the round-about assignment of the `.init.prototype':

    // Give the init function the jQuery prototype for later instantiation
    init.prototype = jQuery.fn;