jQuery 原始碼解析程式碼及更多學習乾貨: 猛戳GitHub
建議下載原始碼然後據文章思路學習,最好自己邊思考邊多敲幾遍。
一:剖析原始碼前準備
- 1.首先官網下載原始碼jQuery官網
- 2.選擇jQuery版本並下載到本地,並在本地給自己新建件
myjQuery-1.0.1.js
(這個檔案是用來仿寫jQuery). - 3.建立入口檔案並引入這官方jQuery和自己建立的
myjQuery-1.0.1.js
檔案. - 4.開始剖析原始碼.
二.開始剖析
本次主要剖析jQuery選擇器的封裝,在平時使用jQuery時,非常容易的通過$()就可以查詢相關的選擇器,那麼具體是如何實現的呢?跟隨我來一探究竟...
首先先來做個例子: 我們先通過官方的jQuery框架輸出以下幾個例項:
// 傳入字串
console.log($("a")); //建立DOM節點包裝成jQuery物件
// 傳入HTML
console.log($("<div>")); // //建立DOM節點包裝成jQuery物件
// 傳入物件
console.log($(document));
// 傳入選擇器
console.log($('.box'));
// 傳入物件
console.log($(this)); // 把傳入的物件包裝成jQuery物件
// 傳入方法
$(function(){
console.log(11111); //這個是在頁面載入完成後載入執行的,等效於在DOM文件載入完成後執行了$(document).read()方法
})
複製程式碼
輸出結果:
根據輸入的結果我們類閱讀原始碼,反推如何實現類似的效果: 首先$()呼叫的是jQuery.prototype.init()的初始化方法,所以要在init()方法裡做擴充套件。以下僅僅是核心的程式碼片段,詳細程式碼在github上,自行下載檢視.
剖析原始碼下載
init:function (selector,context) {
context = context || document;
var match,elem,index=0;
if(!selector){
return this;
}
/**
* 檢測傳過來的資料是否是字串
* **/
if(typeof selector === "string"){
if (selector.charAt(0) === "<" && selector.charAt(selector.length-1)=== ">" && selector.length>=3) {
// 此時是HTML
match = [selector];
}
// match 有值的情況
if (match) {
/**
* 合併陣列
* merge parseHTML是靜態擴充套件方法
* **/
jQuery.merge(this, jQuery.parseHTML(selector,context));
// 查詢DOM節點
} else {
elem = document.querySelectorAll(selector);
// 轉化為真陣列
var elems = Array.prototype.slice.call(elem);
this.length = elem.length;
for (;index = elem.length;index ++) {
this[index] = elems[index];
}
this.context = context;
this.selector = selector;
}
// HANDLE: $(DOMElement)
} else if (selector.nodeType){ //
this.context = this[0] = selector;
this.length = 1;
return this;
// $(function)
// 函式處理
} else if (isFunction( selector )) {
jQuery(document).ready(selector); // 例項物件的方法
}
/**
*makeArray 是jQuery擴充套件的方法
**/
return jQuery.makeArray( selector, this );
},
複製程式碼
jQuery 擴充套件的靜態方法
/**
* 合併陣列
* [first] jQuery的例項物件 this
* [second] DOM 節點
*/
merge:function (first,second) {
var l = second.length, // 1
i = first.length, // 0
j = 0;
if (typeof l === "number") {
for ( ; j < l; j++){ // 遍歷DOM節點
first[i++] = second[j];
}
} else {
while (second[j] !== undefined) {
first[i++] = second[j++];
}
}
first.length = i;
// 返回jQuery的例項物件
return first;
},
/**
* 解析HTML
* [data] 傳入的資料
* [context] 返回的值
* **/
parseHTML:function (data,context) {
if (!data || typeof data !== "string") {
return null;
}
/**
* exec() 是正則方法 返回為陣列
* [0] 為正規表示式相匹配的文字
* [1] 表示式相匹配的文字
* **/
// 過濾掉符號,只提取標籤 "<a>" ==> "a"
var parse = rejectExp.exec(data);
// 返回一個建立DOM的元素
return [context.createElement(parse[1])];
},
/**
* 將一個類陣列物件轉換為真正的陣列物件
* [arr] 傳入的陣列
* [result] 返回的陣列
* **/
makeArray:function(arr,result){
var ret = result || [];
if ( arr != null ) {
if ( isArrayLike( Object( arr ) ) ) {
jQuery.merge( ret,
typeof arr === "string" ?
[ arr ] : arr
);
} else {
[].push.call( ret, arr );
}
}
return ret;
},
isReady:false,
readylist:[],// list
ready:function(){ // 事件函式
jQuery.isReady = true;
jQuery.readylist.forEach(function(callback){
callback.call(document);
})
// 清空
jQuery.readylist = null;
}
});
複製程式碼
/**
* 定義全域性函式
* **/
// 判斷是否是方法
var isFunction = function isFunction( obj ) {
return typeof obj === "function" && typeof obj.nodeType !== "number";
};
// 判斷是否是windows
var isWindow = function isWindow( obj ) {
return obj != null && obj === obj.window;
};
複製程式碼
通過以上程式碼可以做以下幾點分析:
1.$()傳過來的selector資料是屬於什麼型別?不同的資料型別,分析不同資料型別的行為,有以下幾種情況:
- 1.1 如果傳過來的資料是字串:那麼要分析字串是否是HTML標籤,如果是HTML那麼就通過正則提取關鍵字並建立一個HTM標籤輸出
- 1.2 如果傳過來的資料是不是html元素,那麼要通過querySelectorAll來查詢過濾,如果可以查詢到是DOM中的選擇器,那麼就遍歷輸出他的值.
- 1.3 如果傳過來的元素是DOM節點,直接返回
- 1.4 如果傳過來的資料是一個物件方法,那麼要通過$(document).read()方法,監聽攔截DOMContentLoaded方法,改變物件方法的指標然後依次加入到陣列中,輸出.
通過剖析jQuery選擇器模組,進行測試:
測試程式碼:
// 建立DOM
// 傳入字串
console.log($("a")); //建立DOM節點包裝成jQuery物件
// 傳入HTML
console.log($("<div>")); // //建立DOM節點包裝成jQuery物件
// 傳入物件
console.log($(document));
// 傳入選擇器
console.log($('.box'));
// 傳入物件
console.log($(this)); // 把傳入的物件包裝成jQuery物件
$(function(){
console.log(11111);
複製程式碼
輸出結果:
至此完美收官 !! ?總結
通過剖析jQuery原始碼選擇器部分,有以下幾點個人收穫:
- 1.jQuery 設計的靜態屬性擴充套件和jQuery的原型鏈屬性擴充套件(例項擴充套件)的巧妙應用
- 2.巧妙應用正則來篩選資料
其他
jQuery 原始碼剖析 系列目錄地址:猛戳GitHub
jQuery 原始碼剖析 系列預計寫十篇左右,旨在加深對原生JavaScript 部分知識點的理解和深入,重點講解 jQuery核心功能函式、選擇器、Callback 原理、延時物件原理、事件繫結、jQuery體系結構、委託設計模式、dom操作、動畫佇列等。
如果有錯誤或者不嚴謹的地方,請務必給予指正,十分感謝。如果喜歡或者有所啟發,歡迎 star⭐️,對作者也是一種鼓勵。
關注公眾號回覆:學習 領取前端最新最全學習資料,也可以進群和大佬一起學習交流