jQuery 學習筆記:jQuery 程式碼結構
這是我學習 jQuery 過程中整理的筆記,這一部分主要包括 jQuery 的程式碼最外層的結構,寫出來整理自己的學習成果,有錯誤歡迎指出。
jQuery 的最外層 $,jQuery
(function (global, factory) {
"use strict";
if (typeof module === "object" && typeof module.exports === "object") { // 判斷是否使用 commonjs 環境
module.exports = global.document ?
factory(global, true) :
function (w) {
if (!w.document) {
throw new Error("jQuery requires a window with a document");
}
return factory(w);
};
} else {
factory(global);
}
})(typeof window !== "undefined" ? window : this, function (window, noGlobal){
if (typeof define === "function" && define.amd) { // 是否使用 AMD 模組化規範
define("jquery", [], function () {
return jQuery;
});
}
var
_jQuery = window.jQuery,
_$ = window.$;
jQuery.noConflict = function (deep) {
if (window.$ === jQuery) {
window.$ = _$;
}
if (deep && window.jQuery === jQuery) {
window.jQuery = _jQuery;
}
return jQuery;
};
if (!noGlobal) {
window.jQuery = window.$ = jQuery;
}
return jQuery;
});
上面是 jQuery-3.3.1 的一部分程式碼,是最外層的一部分,包含了大量的資訊。
(function (global, factory) {
})(typeof window !== "undefined" ? window : this, function (window, noGlobal){
});
jQuery 程式碼包含在一個自執行的函式內,然後返回出一個指向 jQuery 的索引,就形成了一個閉包,利用 jQuery 物件,可以訪問定義在自執行函式內的方法,在外面則訪問不到,防止變數命名同外界產生衝突,同時,window 物件作為引數傳入函式,在函式內,將 jQuery 和 $ 掛載到 window 物件物件上,這樣,在外界也可以直接通過 window.$ 和 window.jQuery 訪問到 jQuery 物件。通常使用較多的 $,實際指的就是 window.$,但通常會省略掉 window 物件。
if (!noGlobal) {
window.jQuery = window.$ = jQuery; // 將 jQuery 和 $ 掛載到 window 物件物件上
}
return jQuery; // 然後返回出一個指向 jQuery 的索引
同時,為了防止不同庫對 $ 的指向產生衝突,jQuery 還可以將 $ 和 jQuery 還原成原來的指向,只要使用 jQuery.noConflict 方法。
var
_jQuery = window.jQuery, // 儲存 window.jQuery 的值
_$ = window.$; // 儲存 window.$ 的值
jQuery.noConflict = function (deep) {
if (window.$ === jQuery) {
window.$ = _$;
}
if (deep && window.jQuery === jQuery) { // 根據引數判斷是否還原 window.jQuery 的值
window.jQuery = _jQuery;
}
return jQuery;
};
先使用 jQuery 和 $ 儲存 window.jQuery 和 window.$ 的原始值,如果呼叫 jQuery.noConflict 方法,判斷傳入的引數,如果引數值為 false,就僅釋放 $,還原為原來的值,如果引數值為 true,就將 window.jQuery 也還原為原來的值。
jQuery 函式的過載
jQuery 在使用時,既可以作為一個函式,直接呼叫 $,傳入引數,也可以將其作為物件,呼叫物件的方法,作為物件的情況之後再討論,先說將 $ 作為函式使用。
由於 jQuery 中同名函式會覆蓋,傳入引數不同時,不能從多個同名函式中選擇某個函式,而且根據函式名選擇唯一的函式,所以當傳入引數種類不同時,就需要根據引數的個數,型別等資訊判斷具體的處理方式了。當呼叫 jQuery 時,指向的是一個函式。
jQuery = function (selector, context) {
return new jQuery.fn.init(selector, context);
},
會直接返回一個以 jQuery.fn.init 為建構函式,new 出的物件。而在 jQuery.fn.init 函式中,則會根據傳入的引數的不同,進行不同的處理。
init = jQuery.fn.init = function (selector, context, root) {
var match, elem;
if (!selector) { // 如果第一個引數為空,直接 return 呼叫函式的物件
return this;
}
root = root || rootjQuery;
if (typeof selector === "string") {
// 引數為字串,進行處理
} else if (selector.nodeType) {
// 引數為元素節點,進行處理
} else if (isFunction(selector)) {
//引數為函式,進行處理
}
return jQuery.makeArray(selector, this);
};
init.prototype = jQuery.fn; // 將 init 函式的原型指定為 jQuery.fn,則 init 建構函式 new 出的物件就都可以直接使用 init 函式的原型也就是 jQuery.fn 包含的方法。
當引數為空時,返回 init 函式的呼叫者,最終,會返回 jQuery,即 $ 物件,可以使用物件上的方法。當第一個引數為字串時,可以是選擇器,html程式碼(會建立DOM元素幷包裝成 jQuery 物件),當為 DOM 物件時,包裝成 jQuery 物件,當為函式時,$(fn)
相當於 $(document).ready(fn)
,會在頁面頁面 DOM 載入完成後呼叫 fn,效能上優於 window.onload。
jQuery 外掛
上面說到,jQuery 可以作為一個物件,使用其繫結的方法,例如 $.trim 方法,可以去除字串兩邊的空格。此外,jQuery 物件的建構函式 init 的原型指向 jQuery.fn,則 DOM 物件被包裝成 jQuery 物件後,就可以呼叫 jQuery.fn 的方法了,例如 $(`p`).css 方法等。這兩種方法都可以新增新的方法,對應了 jQuery 的兩種外掛。
新增外掛使用的是 jQuery.extend 函式,以及 jQuery.fn.extend,其實指向的是同一個函式,只是函式的呼叫者不同,this 指向就不同了。
$.extend 函式本身可以作為一個工具函式,處理物件的合併,語法 jQuery.extend([deep], target, object1, [objectN])
,這個函式會判斷第一個引數是否是一個 Boolean 值(可選),如果是,則進行深拷貝,如果不是,則進行淺拷貝。然後根據除了 Boolean 值之外的其他引數的個數,判斷是否是新增外掛,如果剩餘引數不止一個,則第一個作為 target,其他物件的屬性將會複製到 target 上,而如果只有一個引數,則會將這個引數物件的方法新增到 jQuery 物件上,或者 jQuery.fn 上,根據呼叫函式的物件不同決定。例如:
:(function($) {
$.fn.extend({ // 引數物件
`color`: function(){ // 物件的屬性將會複製到 $.fn 上
// 外掛程式碼
},
`border`: function () {
// 外掛程式碼
}
});
})(jQuery);
jQuery 本身的程式碼中,也大量使用了 $.extend 方法。這個方法可以和 Object.assign() 對照學習。
資料: