jQuery內核詳解與實踐讀書筆記2:破解jQuery選擇器接口1

前兩篇已經介紹瞭如何搭建一個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,若有興趣敬請關注,主要內容是一個碼農的所見所思所嘆,或掃描下方二維碼關注:

相關文章
相關標籤/搜索