jQuery基本框架解析

我们研究一下jQuery的源码

编码方法很简单。 下面是全部代码的开头和结尾。

(function( window, undefined ) {
 
var document = window.document,
    navigator = window.navigator,
    location = window.location;
 
    [...] // The main sources are here
     
window.jQuery = window.$ = jQuery;
})(window);

  

核心

下面是主要代码的缩减版,可以看到很多块代码。

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; })();

上面代码中jQuery对象的构造函数, jQuery、$和 rootjQuery(一个指向文档的jQuery对象)。

下面代码解释为什么我们可以用"."和"[]"操作变量jQuery对象。

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

对象的构造

这里是jQuery函数的最神圣的地方。jQuery的prototype的魔力隐藏在这里。

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

当你调用jQuery函数式,紧接着新建一个“jQuery.fn.init” 对象并返回。 参看下面代码:

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;

至此, 我们可以知道jQuery.fn等同于jQuery prototype,同时,jQuery.fn.init.prototype指向jQuery prototype, jQuery.fn.init.prototype constructor指向jQuery。这些信息给了我们一个有意思的结论:输入以下代码

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

为了帮助理解,请再看下面的例子:

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

可以看出,所有的结构都在一个jQuery.fn.init对象函数里,而jQuery是生产所有jQuery.fn.init对象的工厂。

解析参数

有很多种应用jQuery函数的方法:

$(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)");

让我们进一步分析jQuery.fn.init函数。

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 );
        }
    }
},

前面四小块代码很简单——当参数分别为空、DOM元素、“body”字符串时如何处理。

Plug-ins Development 创建插件

很多专业人士都知道js的类可以很简单地通过prototypes进行扩展。

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!

我们可以用同样方法对标准JQuery进行扩展。

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

但是,我们已知fn等于jQuery.prototype,所以可以简写如下:

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

因为插件会添加属性到所有已存在的实体和将来要新建的实体,所以如果想针对地对某一对象添加属性,可以用静态属性:

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

小插件的最佳模式:

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);