上一篇jQuery分析(2)中瞭解了jQuery庫的骨架實現原理,這就比如搖滾音樂,搖滾音樂不是某種音樂他就像一個音樂盒子,裏面包含了各類不一樣的搖滾風格(山地、朋克、鄉村、流行、硬搖、金屬、迷幻等)。那麼上一篇只是大體瞭解了jQuery的基本形狀,從這篇文章開始會深刻jQuery庫的各類函數,深刻詳細的去了解他,那將值得慢慢探索,發現新的神奇好玩的東西。javascript
在jQuery.fn.init方法裏面使用到了一些jQuery的靜態函數,在這裏提早統一的介紹html
下面圖是jQeury的構造函數參數即$()調用的參數種類集合圖
java
下面的代碼是可能處理各類參數的方式,多餘的代碼我已刪除掉,下面代碼清晰看到selector無非就是三種類型:一、字符串 二、DOMElement 三、函數。下面將會就這三種類型進行詳細深刻的分析他們的實現原理,這將須要一步一步來理解,首先腦子裏要清晰每一步作了什麼爲何這樣作,這樣一步一步下來才能更好的去理解jQuery的寫法。node
// 匹配html標籤寫法和id選擇器 // 第一個分組是 <div> 中的div,第二個分組是#id中的id rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, jQuery.fn.init = function(selector, context, root) { var match, elem; // 沒有selector將會返回當前this,以便建立空的jQuery對象在後面會用到。 if (!selector) { return this; } // 得到初始化文檔的jQuery對象 root = root || rootjQuery; // 處理參數爲字符串參數 if (typeof selector === "string") { // 處理參數爲DOM節點 } else if (selector.nodeType) { // 處理參數爲function } else if (jQuery.isFunction(selector)) { } // 處理參數爲NodeLists return jQuery.makeArray(selector, this); }; // init函數繼承jQuery init.prototype = jQuery.fn; // 初始化document爲jQuery對象 rootjQuery = jQuery( document );
由於這個jQuery.fn.init函數代碼不少因此單獨的參數類型會把他的代碼單獨提出來分解,下面看提出來的參數爲字符串的代碼。jquery
對於字符串參數的幾種調用方法參見上面腦圖ios
// 匹配html標籤寫法和id選擇器 // 第一個分組是 <div> 中的div,第二個分組是#id中的id rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, // 參數爲字符串處理方式 if (typeof selector === "string") { if (selector.charAt(0) === "<" && selector.charAt(selector.length - 1) === ">" && selector.length >= 3) { // 字符串是單標籤的DOM格式直接建立正則匹配的格式以跳過正則匹配以節約性能 match = [null, selector, null]; } else { // 匹配到DOM字符串 或者ID選擇器 match = rquickExpr.exec(selector); } // 若是selector是一個html字符串或者是一個ID選擇器 if (match && (match[1] || !context)) { // html字符串解析 if (match[1]) { context = context instanceof jQuery ? context[0] : context; // 解析html(單標籤或多標籤) jQuery.merge(this, jQuery.parseHTML( match[1], context && context.nodeType ? context.ownerDocument || context : document, true )); // 構建html元素時傳遞了第二個參數爲一個對象,那麼會對對象的key和value進行解析 if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) { for (match in context) { // Properties of context are called as methods if possible if (jQuery.isFunction(this[match])) { this[match](context[match]); // ...and otherwise set as attributes } else { this.attr(match, context[match]); } } } return this; // id選擇器處理方式 } else { elem = document.getElementById(match[2]); // Check parentNode to catch when Blackberry 4.6 returns // nodes that are no longer in the document #6963 if (elem && elem.parentNode) { // Handle the case where IE and Opera return items // by name instead of ID if (elem.id !== match[2]) { return rootjQuery.find(selector); } // Otherwise, we inject the element directly into the jQuery object this.length = 1; this[0] = elem; } this.context = document; this.selector = selector; return this; } // 其餘選擇器(class、element、attr)等 } else if (!context || context.jquery) {