Design, CG Graphics & Inspiration

The Structure of jQuery: Dive Into Source Code

jQuery definitely has become a standard in web development industry. There are many excellent js-frameworks that deserve attention, but jQuery impressed everyone with its ease, elegance and magic. People write using jQuery, people write plugins for jQuery, people even write articles about jQuery, but few people know (especially beginners) about jQuery’s structure.

In this article, we will hold a small excursion into the interior of this framework and discuss what’s inside of it. This article is intended for basic knowledge of Javascript. Think about it, and if you know how to write a clone of jQuery, then likely you won’t find here anything new.

Overview

jQuery is a Javascript-library. Official Site – jquery.com, author – John Resig, aka jeresig, known guru and a former evangelist of Javascript in Mozilla Corporation. He has his own blog – ejohn.org/, where he wrote a bunch of cool articles and lib for working with Canvas – processing.js, as well as a book “JavaScript. Professional programming techniques.” Located in the Hall of Fame RIT.

The main jQuery repository is located on GitHub, where sources, unit-tests, the collector, js-lint checker etc are stored. At this point I would like to digress and focus on GitHub. A huge number of OpenSource Javascript Lib – prototype.js, MooTools, node.js, jQuery, Raphael, LibCanvas, YUI as well as much of the Javascript (and not only Javascript) community found a refuge there, because if you want to post your javascript-project then GitHub is the best place.

In the directory / src sources are broken into multiple files. If you looked at code.jquery.com/jquery- *. js file and horrified, as you were confused, then you should know – everything is structured and not so terrible. Collected by builder on node.js. The lines of its source “@ VERSION” and “@ DATE” are replaced by any appropriate values.

Let’s Delve Into the Sources

Coding styles are very familiar and ordinary. Tabs and Egyptian brackets are used here. Unlike # indentation, alignment is not used anywhere else.

There are two files – intro.js and outro.js, which are placed at the beginning and at the end of the collected source code, respectively.

(function( window, undefined ) {

var document = window.document,
	navigator = window.navigator,
	location = window.location;

	[...] // The main sources are here
	
window.jQuery = window.$ = jQuery;
})(window);

Core

The core.js file is of primary interest to us, which contains all the stuff. The Source looks like this. We see that the code went down on one more level of nesting, which makes it easier to control the scope of variables:

var jQuery = (function () {
	var jQuery = function ( selector, context ) {
		 return new jQuery.fn.init( selector, context, rootjQuery );
	};
	
	// Map over jQuery in case of overwrite
	_jQuery = window.jQuery,

	// Map over the $ in case of overwrite
	_$ = window.$,

	// A central reference to the root jQuery(document)
	rootjQuery,

	[...]
	
	rootjQuery = jQuery(document);
	
	[...]
	
	return jQuery;
})();

In the copied section you can see the constructor of jQuery-object, stored and current values of jQuery and $ (need more in order to realize jQuery.noConflict ()) as well as a rootjQuery – a jQuery object with reference to the document (cash often find $ (document), optimization).

Just below – series of RegExp that are required for jQuery.browser implementation, jQuery.trim, parsing json etc. Modern browsers support ”.trim and []. IndexOf methods, because jQuery has retained links to them and uses the native implementation in their jQuery.trim and jQuery.inArray.

trim = String.prototype.trim,
indexOf = Array.prototype.indexOf,

Object’s Construction

We get to the “holy of holies” jQuery – $-function. This part – the hardest piece for those who didn’t use to it, that’s why we should approach it with a clear head:) jQuery prototypes’ magic is hidden here, I will not go into details as to why it works this way, only will tell you how it works. We have already seen the jQuery’s constructor code above:

var jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
	return new jQuery.fn.init( selector, context, rootjQuery );
},

That is, when you call the jQuery functions the “jQuery.fn.init” essence creates and returns. Here the magic of Javascript is used. In the code below we can find something like this:

jQuery.fn = jQuery.prototype = {
	constructor: jQuery,
	init: function( selector, context, rootjQuery ) {
		[...]
	}
	[...]
}

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

From now on, we know that jQuery.fn is nothing more than a jQuery prototype and this knowledge will help us to sort out something below. Also, jQuery.fn.init.prototype points at jQuery prototype, and jQuery.fn.init.prototype constructor points at jQuery. This approach gives us a very interesting result. Open jQuery, Chrome console and type:

$(document) instanceof jQuery; // true
$(document) instanceof jQuery.fn.init; // true

To help you understand the essence of this behavior, I’ll give you another example:

var Init = function () {
	console.log('[Init]');
};

var jQuery = function () {
	console.log('[jQuery]');
	return new Init();
};

Init.prototype = jQuery.prototype = {
	constructor: jQuery
};

var $elem = jQuery(); // [jQuery] , [Init]

console.log( $elem instanceof jQuery ); // true
console.log( $elem instanceof Init   ); // true

Thus, all the construction is in a jQuery.fn.init object-function , and jQuery is a factory of jQuery.fn.init objects.

Parse the Arguments

There are lots of options for using jQuery function:

$(function () { alert('READY!') }); // Function to be executed only when loading a DOM
$(document.getElementById('test')); // link on the element
$('<div />'); // create new element
$('<div />', { title: 'test' }); // create new element with attributes

// Supports all imaginable and unimaginable css-selectors:
$('#element'); // element with ip "element"
$('.element', $previous ); // Find all elements with a class element in $ previous
$("div[name=city]:visible:has(p)"); 

Let’s get into the constructor, which, as we already know is jQuery.fn.init. Here I’ll give a pseudocode:

init: function( selector, context, rootjQuery ) {
	if ( !selector ) return this;

	// Handle $(DOMElement)
	if ( selector.nodeType ) return this = selector;

	// The body element only exists once, optimize finding it
	if ( selector === "body" && !context ) return this = document.body;

	if ( jQuery.isFunction( selector ) ) {
		return rootjQuery.ready( selector );
	}

	// Handle HTML strings
	if ( typeof selector === "string" ) {
		// Verify a match, and that no context was specified for #id
		if ( selector.match(quickExpr) ) {
			if ( match[1] ) {
				return createNewDomElement( match[1] );
			} else {
				return getById( match[2] )
			}
		} else {
			return jQuery( context ).find( selector );
		}
	}
},

The first four pieces are quite clear – it is about the cases that are being processed when an empty selector, DOM-element as a selector or the string ‘body’ was passed , for more rapid receipt of the document body, and processing functions for DomReady.

An interesting point with the case when we pass a line. First of all, it parses its “fast regular expression.” It left side is responsible for finding the tag line, and the second – the search for Id element:

quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/;

And only if the request is more complex, we call the find method in the current context that looks for an element using the search engine (also JResig) Sizzle (Copyright The Dojo Foundation).

Plug-ins Development

Many professionals are aware of Javascript that a class created with the help of prototypes can be very easily extended.

var MyClass = function () {
	// constructor
};

MyClass.prototype = {
	// prototype
};

var instance = new MyClass();

// We can extend the class prototype and new features will be added to all entities, even those whichvare already created

MyClass.prototype.plugin = function () {
	console.log("He's alive!");
};

instance.plugin(); // He's alive!

In the same way we can expand the standard jQuery prototype:

jQuery.prototype.plugin = function () {
	// Here is my plugin
};

But, as we have seen above, fn is a brief link on jQuery.prototype, that’s why you can write shorter:

jQuery.fn.plugin = function () {
	// Here is my plugin
	// This here refers to jquery-object, from which the method is called
};

And this plugin will appear in all the entities that already created and those that will be created. Adding properties directly to the object, we implement the static properties:

jQuery.plugin = function () {
	// Here is my plugin
};

Thus, the best pattern for smaller plug-ins:

new function (document, $, undefined) {
	
	var privateMethod = function () {
		// private method, used for plugin
	};
	
	$.fn.myPlugin = function () {
		
	};
	
	// and if you need a method that is not bound to the dom-elements:
	$.myPlugin = function () {
		
	};
	
}(document, jQuery);

This approach can be seen in the majority of plugins for jQuery, for example, DatePicker.

Conclusion

In my opinion the reason of jQuery’s popularity was the external simplicity and ease, as well as shortness of names: css vs. setStyles, attr against setAttributes etc. The idea was simply wonderful and captivated the minds of many people.

One can often meet jQuery clones or ideas that are carried into other languages. But the simplicity is deceptive. And it is not always good, so you should always think twice before you cut the clear name of the method, because it canturn out wrong for you.

You might also be interested in..

JavaScript and jQuery: 50 New Tutorials
50 jQuery Tutorials And Techniques
Fixing animation in jQuery

SHARE THIS POST

Pavel is 21 year old web developer from Ukraine. In his spare time he writes articles about the basics of LibCanvas, AtomJS and JavaScript

Subscribe for the hottest posts

Subscribe to our email newsletter for useful tips and freebies.

  • Nice post.

  • pratt

    you misspelled definitely (second word, first sentence).

  • shorst

    Wow, this was enlightening. Thank you very much.

  • Nice post.

  • pratt

    you misspelled definitely (second word, first sentence).

  • shorst

    Wow, this was enlightening. Thank you very much.