jQuery unveiled: library initialization

jQuery's initialization requires two steps: first the library creates the fn alias for its prototype object, then it performs the necessary steps to handle CSS-like selector chain. Here's the code:

jQuery.fn = jQuery.prototype = {
 init: function( selector, context ) {
  var match, elem, ret, doc;

  // Handle $(""), $(null), or $(undefined)
  if ( !selector ) {
   return this;
  }

  // Handle $(DOMElement)
  if ( selector.nodeType ) {
   this.context = this[0] = selector;
   this.length = 1;
   return this;
  }
  
  // The body element only exists once, optimize finding it
  if ( selector === "body" && !context ) {
   this.context = document;
   this[0] = document.body;
   this.selector = "body";
   this.length = 1;
   return this;
  }

  // Handle HTML strings
  if ( typeof selector === "string" ) {
   // Are we dealing with HTML string or an ID?
   match = quickExpr.exec( selector );

   // Verify a match, and that no context was specified for #id
   if ( match && (match[1] || !context) ) {

    // HANDLE: $(html) -> $(array)
    if ( match[1] ) {
     doc = (context ? context.ownerDocument || context : document);

     // If a single string is passed in and it's a single tag
     // just do a createElement and skip the rest
     ret = rsingleTag.exec( selector );

     if ( ret ) {
      if ( jQuery.isPlainObject( context ) ) {
       selector = [ document.createElement( ret[1] ) ];
       jQuery.fn.attr.call( selector, context, true );

      } else {
       selector = [ doc.createElement( ret[1] ) ];
      }

     } else {
      ret = buildFragment( [ match[1] ], [ doc ] );
      selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes;
     }
     
     return jQuery.merge( this, selector );
     
    // HANDLE: $("#id")
    } else {
     elem = document.getElementById( match[2] );

     if ( elem ) {
      // Handle the case where IE and Opera return items
      // by name instead of ID
      if ( elem.id !== match[2] ) {
       return rootjQuery.find( selector );
      }

      // Otherwise, we inject the element directly into the jQuery object
      this.length = 1;
      this[0] = elem;
     }

     this.context = document;
     this.selector = selector;
     return this;
    }

   // HANDLE: $("TAG")
   } else if ( !context && /^\w+$/.test( selector ) ) {
    this.selector = selector;
    this.context = document;
    selector = document.getElementsByTagName( selector );
    return jQuery.merge( this, selector );

   // HANDLE: $(expr, $(...))
   } else if ( !context || context.jquery ) {
    return (context || rootjQuery).find( selector );

   // HANDLE: $(expr, context)
   // (which is just equivalent to: $(context).find(expr)
   } else {
    return jQuery( context ).find( selector );
   }

  // HANDLE: $(function)
  // Shortcut for document ready
  } else if ( jQuery.isFunction( selector ) ) {
   return rootjQuery.ready( selector );
  }

  if (selector.selector !== undefined) {
   this.selector = selector.selector;
   this.context = selector.context;
  }

  return jQuery.makeArray( selector, this );
 },

The private init() method actually loads the core of the jQuery library, namely the selector chain syntax. Here are its progressive steps:

  1. a reference to a null or undefined value is handled by binding the current selection to this, that is, to jQuery itself
  2. the syntax $(selector)[0] allows you to use W3C DOM core methods on a selector chain
  3. a reference to the body element is optimized for a better performance
  4. by using its library constants, jQuery handles the following combinations:
    1. HTML strings
    2. a reference to an ID selector ($('#id'))
    3. a reference to one or more generic simple selectors or descendant selectors
    4. a reference to a complex expression
    5. the shortcut $(function) which is an alias for $(document).ready()

This entry was posted in by Gabriele Romanato. Bookmark the permalink.

Leave a Reply

Note: Only a member of this blog may post a comment.