jQuery Source Code Architecture Explained
This article breaks down the internal architecture of the jQuery
source code, detailing how the library is structured, initialized, and
executed. It covers the core design patterns used by jQuery, including
its Immediately Invoked Function Expression (IIFE) wrapper, the factory
pattern that eliminates the need for the new keyword, the
prototype alias mechanism (jQuery.fn), the internal
extension system, and how specialized sub-modules like Sizzle, the Event
system, and Ajax interact to create a cohesive, chainable library.
The Self-Executing Wrapper (IIFE)
The entirety of jQuery's source code is wrapped in an Immediately Invoked Function Expression (IIFE) or Universal Module Definition (UMD) pattern. This pattern prevents variable leakage into the global scope and encapsulates internal implementation details.
(function(global, factory) {
"use strict";
if (typeof module === "object" && typeof module.exports === "object") {
// CommonJS / Node environment
module.exports = global.document ?
factory(global, true) :
function(w) {
if (!w.document) {
throw new Error("jQuery requires a window with a document");
}
return factory(w);
};
} else {
// Browser environment
factory(global);
}
})(typeof window !== "undefined" ? window : this, function(window, noGlobal) {
// jQuery core implementation lives here
});By passing window (or global) into the
factory function, jQuery localizes the reference, which speeds up
variable resolution and enables minifiers to compress the reference into
a single character.
The Factory Function and Prototype Architecture
One of jQuery's defining design choices is allowing users to invoke
$() without typing new $(). To accomplish
this, jQuery uses a factory pattern linked directly to its
prototype.
jQueryDeclaration: ThejQueryvariable is defined as a function that returns an instance of an internal constructor namedjQuery.fn.init.jQuery.fnAlias: jQuery setsjQuery.fn = jQuery.prototypeas a shorthand.initPrototype Reassignment: The prototype ofjQuery.fn.initis pointed back tojQuery.fn.
var jQuery = function(selector, context) {
return new jQuery.fn.init(selector, context);
};
jQuery.fn = jQuery.prototype = {
constructor: jQuery,
length: 0,
// core prototype methods...
};
var init = jQuery.fn.init = function(selector, context, root) {
// DOM selection and parsing logic
return this;
};
// Crucial link: allows instances created by init to inherit jQuery.fn methods
init.prototype = jQuery.fn;When a user calls $('div'), an instance of
init is instantiated, but because
init.prototype references jQuery.fn, the
returned object inherits all jQuery methods.
Method Chaining
jQuery enables fluent chaining by ensuring that methods that mutate
or query the collection return the calling instance (this).
If a method creates a new set of elements (such as .find()
or .filter()), it builds a new jQuery instance using
.pushStack(), which maintains a reference to the previous
state (prevObject) so users can revert back using
.end().
The Extension Mechanism:
jQuery.extend
The extend method is the structural engine for
modularity in jQuery. It merges the contents of two or more objects
together into the first object.
jQuery.extend: Extends the jQuery static object directly with utility methods (e.g.,$.ajax,$.each).jQuery.fn.extend: Extends the jQuery prototype, adding instance methods available to element collections (e.g.,.addClass,.css).
Both functions point to the exact same implementation:
jQuery.extend = jQuery.fn.extend = function() {
// Copies properties from source objects to target object
};This single method serves as both the internal module assembler and the external plugin interface.
Modular Sub-Systems
The jQuery codebase divides its responsibilities into separate, decoupled modules:
- Core & Accessors: Handles instance creation,
type checking, iteration (
each,map), and array manipulation. - Selector Engine (Sizzle): An integrated engine (or
modern
querySelectorAllwrapper) that parses complex CSS selectors and traverses the DOM. - Data Storage (
Data): Manages metadata associated with DOM elements without creating memory leaks caused by circular references between JavaScript and DOM objects. - Callbacks & Deferreds: A custom implementation of asynchronous control flow and promises that powers both internal queues and external API operations.
- Queue: Manages execution queues, heavily used by the animation subsystem.
- Event System: Normalizes cross-browser event handling, bubbling, and delegation via an internal cache rather than binding directly to raw DOM nodes repeatedly.
- DOM Manipulation: Methods for inserting, wrapping, cloning, and removing DOM nodes safely, managing cleanup of event listeners and cached data.
- CSS & Dimensions: Computes style values, polyfills browser quirks, and retrieves layout dimensions (width, height, offsets).
- Ajax: Implements
XMLHttpRequestwrappers with support for custom data transports, JSONP, and promises.
Global Exposure and
noConflict
At the conclusion of the factory function, jQuery binds itself to the
global environment while saving any prior values assigned to
$ or jQuery to support multi-library
compatibility:
var _jQuery = window.jQuery,
_$ = window.$;
jQuery.noConflict = function(deep) {
if (window.$ === jQuery) {
window.$ = _$;
}
if (deep && window.jQuery === jQuery) {
window.jQuery = _jQuery;
}
return jQuery;
};
if (!noGlobal) {
window.jQuery = window.$ = jQuery;
}This allows developers to relinquish control of the $
shortcut back to other libraries (such as Prototype or MooTools) when
required.