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