這是我學習 jQuery 過程當中整理的筆記,這一部分主要包括 jQuery 的代碼最外層的結構,寫出來整理本身的學習成果,有錯誤歡迎指出。javascript
(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 的一部分代碼,是最外層的一部分,包含了大量的信息。css
(function (global, factory) { })(typeof window !== "undefined" ? window : this, function (window, noGlobal){ });
jQuery 代碼包含在一個自執行的函數內,而後返回出一個指向 jQuery 的索引,就造成了一個閉包,利用 jQuery 對象,能夠訪問定義在自執行函數內的方法,在外面則訪問不到,防止變量命名同外界產生衝突,同時,window 對象做爲參數傳入函數,在函數內,將 jQuery 和 $ 掛載到 window 對象對象上,這樣,在外界也能夠直接經過 window.$ 和 window.jQuery 訪問到 jQuery 對象。一般使用較多的 $,實際指的就是 window.$,但一般會省略掉 window 對象。html
if (!noGlobal) { window.jQuery = window.$ = jQuery; // 將 jQuery 和 $ 掛載到 window 對象對象上 } return jQuery; // 而後返回出一個指向 jQuery 的索引
同時,爲了防止不一樣庫對 $ 的指向產生衝突,jQuery 還能夠將 $ 和 jQuery 還原成原來的指向,只要使用 jQuery.noConflict 方法。java
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 也還原爲原來的值。node
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 能夠做爲一個對象,使用其綁定的方法,例如 $.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() 對照學習。
資料: