前兩篇已經介紹瞭如何搭建一個jQuery框架的雛形,從這一篇開始詳細瞭解jQuery選擇器的接口。jQuery選擇器功能強大但用法很簡單,它僅僅提供了一個接口:jQuery(),也能夠簡寫爲$()。html
1. 簡單但很複雜的黑洞node
jQuery提供了惟一的接口(jQuery()或$())使選擇器與外界進行交流。
jQuery框架的基礎是查詢,即查詢文檔元素對象,所以能夠認爲jQuery對象就是一個選擇器,並在此基礎上構建和運行查詢過濾器。
jQuery查詢結果的數據集合是jQuery對象的一部分。
在$()函數中能夠包含選擇字符串,HTML字符串,DOM對象和數據集合等不一樣類型的參數。jQuery是如何分辨這些參數呢?
爲了方便理解其中的奧祕,把jQuery框架進行簡化,先刪除全部方法,函數以及邏輯代碼,而後在init()構造器中,使用alert()方法獲取selector參數的類型和信息,代碼以下:正則表達式
1 (function() { 2 var window = this; 3 jQuery = window.jQuery = window.$ = function(selector, context) { 4 return new jQuery.fn.init(selector, context); 5 }; 6 jQuery.fn = jQuery.prototype = { 7 init : function(selector, context) { 8 alert(selector); 9 } 10 }; 11 })(); 12 window.onload = function() { 13 $("div.red");//獲取"div.red" 14 $("div .red");//獲取"div .red" 15 $(document.getElementById("wrap"));//獲取"[object HTMLDivElement]" 16 $("#wrap", document.forms[0]);//獲取"wrap" 17 $("<div>hello, world</div>");//獲取"<div>hello, world</div>" 18 };
2. 盤根錯節的邏輯關係express
jQuery()的4種構建jQuery對象的方式:數組
jQuery(expression, [context])瀏覽器
jQuery(html, [ownerDocument])微信
jQuery(elements)數據結構
jQuery(callback)框架
jQuery對象的方法都是針對DOM元素對象進行的操做。函數
jQuery對象就是jQuery.fn.init構造器建立的對象,而經過jQuery.fn.init.prototype = jQuery.fn途徑,再使用jQuery的原型對象去覆蓋jQuery.fn的原型對象,使得jQuery對象的原型方法也就被繼承過來,從而造成了錯綜複雜但又井井有理的關係。
3. jQuery構造器
jQuery的構造器就是jQuery.fn.init()函數,它負責對傳入的參數進行分析,而後生成並返回jQuery對象。這個函數的第一個參數是必需的,若是爲空,則默認爲document。
從本質上講,使用jQuery選擇器(即jQuery.fn.init()構造器)構建jQuery對象,就是在this對象上附加DOM元素集合,附加的方式包括如下兩種:
1. 若是是單個DOM元素,能夠直接把DOM元素做爲數組元素傳遞給this對象,還能夠經過ID從DOM文檔中查詢元素
2. 若是是多個DOM元素,則以集合方式附加,如jQuery對象、數組和對象等,此時能夠經過CSS選擇器匹配到全部DOM元素,而後過濾,最後構建類數組的數據結構
其中,CSS選擇器是經過jQuery().find(selector)函數來完成的。經過jQuery().find(selector)能夠分析選擇器字符串,並在DOM文檔樹中查找到符合語法的元素集合。
下面先來分析一下init()初始化構造器函數,來分析jQuery選擇器是如何工做的。
1 /** 2 * jQuery構造器源碼分析, 3 * 注意該書是以jQuery的1.3版原本分析的,與當前Github上的源碼的init函數有必定的出入, 4 * 可是總體的思路是差很少的,只是具體的實現方式有所不一樣而已, 5 */ 6 //jQuery原型函數,構造jQuery對象的入口 7 //全部jQuery對象方法都經過jQuery原型對象來繼承 8 jQuery.fn = jQuery.prototype = { 9 /* 10 * jQuery對象初始化構造器,至關於jQuery對象的類型,有該函數負責建立jQuery對象 11 * 參數說明: 12 * selector:選擇器的符號,能夠是任意數據類型。考慮DOM元素操做須要,該函數應該是包含DOM元素的任何數據 13 * context:上下文,指定在文檔DOM中哪一個節點下開始進行查詢,默認值爲document 14 */ 15 init : function(selector, context) { 16 selector = selector || document; //確保selector參數存在,默認值爲document 17 /* 18 * 第一種狀況,處理選擇符爲DOM元素,此時將忽略上下文,即忽略第二個參數 19 * 例如,$(document.getElementById("wrap")),jQuery(DOMElement)匹配DOM元素。 20 * 先使用selector.nodeType判斷當selector爲元素節點,將length設置爲1, 21 * 而且賦值給context,實際上context做爲init的第二個參數, 22 * 也意味着它的上下文節點就是selector該節點,返回它的$(DOMElement)對象 23 */ 24 if(selector.nodeType) { //存在nodeType屬性,說明選擇符是一個DOM元素 25 this[0] = selector; //直接把當前參數的DOM元素存入類數組中 26 this.length = 1; //設置類數組的長度,以方便遍歷訪問 27 this.context = selector; //設置上下文屬性 28 return this; //返回jQuery對象,即類數組對象 29 } 30 31 //若是選擇符參數爲字符串,則進行處理 32 //例如,$("<div>hello, world</div>"),jQuery(html, [ownerDocument])匹配HTML字符串 33 if(typeof selector == "string") { 34 //使用quickExpr正則表達式匹配該選擇符字符串,決定是處理HTML字符串,仍是處理ID字符串 35 quickExpr = /^[^<]*(<(.|\s)+>[^>]*$|^#([\w-]+)$)/; 36 var match = quickExpr.exec(selector); 37 //驗證匹配的信息 38 if(match && (match[1] || !context)) { 39 /* 40 * 第二種狀況,處理HTML字符串,相似$(html) -> $(array) 41 */ 42 if(match[1]) { 43 selector = jQuery.clean([match[1]], context); 44 } 45 /* 46 * 第三種狀況,處理ID字符串,相似$("#id") 47 */ 48 else { 49 var elem = document.getElementById(match[3]); //獲取該元素確保該元素存在 50 //處理在IE和Opera瀏覽器下根據name,而不是根據ID返回元素 51 if(elem && elem.id != match[3]) { 52 return jQuery().find(selector); //默認調用document.find()方法 53 } 54 //不然將把elem做爲元素參數直接調用jQuery()函數,返回jQuery對象 55 var ret = jQuery(elem || []); 56 ret.context = document; //設置jQuery對象的上下文屬性 57 ret.selector = selector; //設置jQuery對象上的選擇符屬性 58 return ret; //返回jQuery對象 59 } 60 } 61 /* 62 * 第四種狀況,處理jQuery(expression, [context]) 63 * 例如,$("div .red")的表達式字符串 64 */ 65 else { 66 return jQuery(context).find(selector); 67 } 68 } else if(jQuery.isFunction(selector)) { 69 /* 70 * 第五種狀況,處理jQuery(callback),即$(document).ready()的簡寫 71 * 例如,$(function() { alert("hello, world");}), 72 * 或者 $(document).ready(function() { alert("hello, world");}) 73 */ 74 return jQuery(document).ready(selector); 75 } 76 //確保舊的選擇符可以經過 77 if(selector.selector && selector.context) { 78 this.selector = selector.selector; 79 this.context = selector.context; 80 } 81 /* 82 * 第六種狀況,處理相似$(elements) 83 */ 84 return this.setArray(jQuery.isArray(selector) ? selector : jQuery.makeArray(selector)); 85 } 86 //其它代碼。。。 87 };
代碼中已經對相關的判斷邏輯作了詳細的說明,這裏就不在作解釋說明了。
今天就先寫到這裏,下一篇內容將是關於jQuery如何生成DOM元素和引用DOM元素。歡迎轉載,轉載請註明出處。
我的微信公衆號:programmlife,若有興趣敬請關注,主要內容是一個碼農的所見所思所嘆,或掃描下方二維碼關注: