最近寫前段的程式碼比較多,jQuery是用的最多的一個物件,但是之前幾次看了原始碼,都沒搞清楚jQuery是怎麼定義的,今天終於看明白怎麼回事了。記錄下來,算是一個新的開始吧。
(文中原始碼都是jQuery-1.10.2版本的)
先上一段jQuery定義的原始碼,定義了jQuery為一個function
1 // Define a local copy of jQuery 2 jQuery = function( selector, context ) { 3 // The jQuery object is actually just the init constructor 'enhanced' 4 return new jQuery.fn.init( selector, context, rootjQuery ); 5 }
這就是我們常用的格式:$("#div1");就是通過這個函式定義的
這個函式只有一行有效程式碼,就是例項化了一個型別,這個型別是在jQuery的原型中定義的,那麼繼續往下看。
1 jQuery.fn = jQuery.prototype = { 2 // The current version of jQuery being used 3 jquery: core_version, 4 5 constructor: jQuery, 6 init: function( selector, context, rootjQuery ) { 7 var match, elem; 8 9 // HANDLE: $(""), $(null), $(undefined), $(false) 10 if ( !selector ) { 11 return this; 12 } 13 14 // Handle HTML strings 15 if ( typeof selector === "string" ) { 16 if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { 17 // Assume that strings that start and end with <> are HTML and skip the regex check 18 match = [ null, selector, null ]; 19 20 } else { 21 match = rquickExpr.exec( selector ); 22 } 23 24 // Match html or make sure no context is specified for #id 25 if ( match && (match[1] || !context) ) { 26 27 // HANDLE: $(html) -> $(array) 28 if ( match[1] ) { 29 context = context instanceof jQuery ? context[0] : context; 30 31 // scripts is true for back-compat 32 jQuery.merge( this, jQuery.parseHTML( 33 match[1], 34 context && context.nodeType ? context.ownerDocument || context : document, 35 true 36 ) ); 37 38 // HANDLE: $(html, props) 39 if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { 40 for ( match in context ) { 41 // Properties of context are called as methods if possible 42 if ( jQuery.isFunction( this[ match ] ) ) { 43 this[ match ]( context[ match ] ); 44 45 // ...and otherwise set as attributes 46 } else { 47 this.attr( match, context[ match ] ); 48 } 49 } 50 } 51 52 return this; 53 54 // HANDLE: $(#id) 55 } else { 56 elem = document.getElementById( match[2] ); 57 58 // Check parentNode to catch when Blackberry 4.6 returns 59 // nodes that are no longer in the document #6963 60 if ( elem && elem.parentNode ) { 61 // Handle the case where IE and Opera return items 62 // by name instead of ID 63 if ( elem.id !== match[2] ) { 64 return rootjQuery.find( selector ); 65 } 66 67 // Otherwise, we inject the element directly into the jQuery object 68 this.length = 1; 69 this[0] = elem; 70 } 71 72 this.context = document; 73 this.selector = selector; 74 return this; 75 } 76 77 // HANDLE: $(expr, $(...)) 78 } else if ( !context || context.jquery ) { 79 return ( context || rootjQuery ).find( selector ); 80 81 // HANDLE: $(expr, context) 82 // (which is just equivalent to: $(context).find(expr) 83 } else { 84 return this.constructor( context ).find( selector ); 85 } 86 87 // HANDLE: $(DOMElement) 88 } else if ( selector.nodeType ) { 89 this.context = this[0] = selector; 90 this.length = 1; 91 return this; 92 93 // HANDLE: $(function) 94 // Shortcut for document ready 95 } else if ( jQuery.isFunction( selector ) ) { 96 return rootjQuery.ready( selector ); 97 } 98 99 if ( selector.selector !== undefined ) { 100 this.selector = selector.selector; 101 this.context = selector.context; 102 } 103 104 return jQuery.makeArray( selector, this ); 105 }, 106 。。。其他方法省略 107 }
在上面這段程式碼中,定義了jQuery的原型,然後將原型賦給了jQuery.fn;$.fn這個東西大家應該都很熟悉了,我們擴充套件jQuery外掛的時候時長用到它,其實就是想jQuery的原型中新增了方法。
在原型的定義中重要的就是init函式了,有三個引數:selector,context,rootjQuery。
在這個函式中根據各種情況做了判斷,比如:selector物件為false時的就是處理$("")或者$(null)或者$(undefined),(註釋上都有說明);
如果selector是function時,就是我們最常用的頁面載入處理函式:$(function(){......});
到這裡,應該就可以明白了,jQuery物件不過是一個函式,然後在內部例項化了一個jQuery.fn.init;
但是問題來了,我們做jQuery外掛的時候,擴充套件的是jQuery.fn,是jQuery的原型,跟jQuery.fn.init的例項化物件沒有關係,這是怎麼回事?
接下來這行程式碼就解決了我的疑惑:
1 // Give the init function the jQuery prototype for later instantiation 2 jQuery.fn.init.prototype = jQuery.fn;
將jQuery原型的定義賦給了jQuery.fn.init的原型,這樣我們在擴充套件jQuery原型的同時,也擴充套件了jQuery.fn.init的原型,那麼jQuery物件就有了那些方法(確切的說應該是jQuery.fn.init型別的例項化物件)
接下來的原始碼定義了jQuery.extend=jQuery.fn.extend=function(){};然後通過這兩個方法新增了預定義的方法和屬性,比如:ready函式、isFunction函式、each函式等等
到這裡差不多jQuery的定義就結束了,我們常用的一些方法也在原始碼中通過extend方法預先定義好了。