jQuery源碼淺析


這幾天看了下jQuery源碼,有些收獲,解答了我以前對jQuery的疑問,現在我把收獲分享給大家。

、jQuery為何弄成自執行函數,以及為何在引用了jquery文件之后,可以通過$或jQuery來調用其方法

(function (window, undefined) {....})(window);
$.isFunction();

   1) 弄成自執行函數: 防止在這里邊 var 定義的變量,屬於這個函數域內的局部變量,避免污染全局,只在后面暴露 $ 和 jQuery 這 2 個變量給外界,盡量的避開變量沖突。

     2)可以通過$或jQuery來調用:在jQuery源碼里有這么一句,將jQuery賦值給window下的jQuery和window下的.$

window.jQuery = window.$ = jQuery;

、為什么需要加上undefined當做參數?

(function (window, undefined) {....})(window);

   jQuery內部有用到undefined作為判斷條件,如果在外部改變了undefined的值,會影響jQuery內部判斷,所以參數里加上undefined就是確保undefined就是undefined,為什么這么說?在早期瀏覽器全局的undefined是可以被賦值的,可以當做變量使用,比如IE9以下,不過在新版瀏覽器里則沒有這個問題,觀察jQuery2.0+發現沒有出現把undefined作為參數傳遞,因為2.0+不再支持IE9以下瀏覽器了。

、為何不用new就能調用jQuery的原型方法,比如$("#id").val()

 1 (function (window, undefined) {
 2     var
 3     // ...
 4     jQuery = function (selector, context) {
 5         //實例化方法 jQuery() 實際上是調用了原型方法 jQuery.fn.init
 6         return new jQuery.fn.init(selector, context, rootjQuery);
 7     };
 8     // jQuery.prototype 即是 jQuery 的原型,掛載在上面的方法,即可讓所有生成的 jQuery 對象使用
 9     jQuery.fn = jQuery.prototype = {
10         // 實例化化方法,這個方法可以稱作 jQuery 對象構造器
11         init: function (selector, context, rootjQuery) {
12             // ...
13         }
14     }
15     //這里將jQuery的原型賦值給init原型,讓init實例化之后可以調用jQuery的原型方法
16     //這也就是為什么實例化init可以調用jQuery的原型val()方法 比如:$("#id").val()
17     jQuery.fn.init.prototype = jQuery.fn;
18 })(window);

、jQuery.fn.extend 與 jQuery.extend有什么區別

     1)jQuery.extend(object) 為擴展 jQuery 類本身,為類添加新的靜態方法;

   2)jQuery.fn.extend(object) 給 jQuery 對象添加實例方法,也就是通過這個 extend 添加的新方法,實例化的 jQuery 對象都能使用,因為它是掛載在 jQuery.fn 上的方法(jQuery.fn =jQuery.prototype )。 

   官方解釋是:

   1)jQuery.extend(): 把兩個或者更多的對象合並到第一個當中,

   2)jQuery.fn.extend():把對象掛載到 jQuery 的 prototype 屬性,來擴展一個新的 jQuery 實例方法。

     使用 jQuery.extend() 擴展的靜態方法,我們可以直接使用 $.xxx 進行調用(xxx是擴展的方法名),像c#中的靜態方法。

   而使用 jQuery.fn.extend() 拓展的實例方法,需要使用 $().xxx 調用,像c#中的實例方法。

 1 // 擴展合並函數
 2 // 合並兩個或更多對象的屬性到第一個對象中,jQuery 后續的大部分功能都通過該函數擴展
 3 // 雖然實現方式一樣,但是要注意區分用法的不一樣,那么為什么兩個方法指向同一個函數實現,但是卻實現不同的功能呢,
 4 // 閱讀源碼就能發現這歸功於 this 的強大力量
 5 // 如果傳入兩個或多個對象,所有對象的屬性會被添加到第一個對象 target
 6 // 如果只傳入一個對象,則將對象的屬性添加到 jQuery 對象中,也就是添加靜態方法
 7 // 用這種方式,我們可以為 jQuery 命名空間增加新的方法,可以用於編寫 jQuery 插件
 8 // 如果不想改變傳入的對象,可以傳入一個空對象:$.extend({}, object1, object2);
 9 // 默認合並操作是不迭代的,即便 target 的某個屬性是對象或屬性,也會被完全覆蓋而不是合並
10 // 如果第一個參數是 true,則是深拷貝
11 // 從 object 原型繼承的屬性會被拷貝,值為 undefined 的屬性不會被拷貝
12 // 因為性能原因,JavaScript 自帶類型的屬性不會合並
13 jQuery.extend = jQuery.fn.extend = function () {
14     var src, copyIsArray, copy, name, options, clone,
15         target = arguments[0] || {},
16         i = 1,
17         length = arguments.length,
18         deep = false;
19 
20     // Handle a deep copy situation
21     // target 是傳入的第一個參數
22     // 如果第一個參數是布爾類型,則表示是否要深遞歸,
23     if (typeof target === "boolean") {
24         deep = target;
25         target = arguments[1] || {};
26         // skip the boolean and the target
27         // 如果傳了類型為 boolean 的第一個參數,i 則從 2 開始
28         i = 2;
29     }
30 
31     // Handle case when target is a string or something (possible in deep copy)
32     // 如果傳入的第一個參數是 字符串或者其他
33     if (typeof target !== "object" && !jQuery.isFunction(target)) {
34         target = {};
35     }
36 
37     // extend jQuery itself if only one argument is passed
38     // 如果參數的長度為 1 ,表示是 jQuery 靜態方法
39     if (length === i) {
40         //此時的this:如果外部調用的是jQuery.extend方法,則this指jQuery類,擴展到jQuery類上
41         //而如果是jQuery.fn.extend方法則this指jQuery原型,擴展到jQuery的原型上
42         target = this;
43         --i;
44     }
45 
46     // 可以傳入多個復制源
47     // i 是從 1或2 開始的
48     for (; i < length; i++) {
49         // Only deal with non-null/undefined values
50         // 將每個源的屬性全部復制到 target 上
51         if ((options = arguments[i]) != null) {
52             // Extend the base object
53             for (name in options) {
54                 // src 是源(即本身)的值
55                 // copy 是即將要復制過去的值
56                 src = target[name];
57                 copy = options[name];
58 
59                 // Prevent never-ending loop
60                 // 防止有環,例如 extend(true, target, {'target':target});
61                 if (target === copy) {
62                     continue;
63                 }
64 
65                 // Recurse if we're merging plain objects or arrays
66                 // 這里是遞歸調用,最終都會到下面的 else if 分支
67                 // jQuery.isPlainObject 用於測試是否為純粹的對象
68                 // 純粹的對象指的是 通過 "{}" 或者 "new Object" 創建的
69                 // 如果是深復制
70                 if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))) {
71                     // 數組
72                     if (copyIsArray) {
73                         copyIsArray = false;
74                         clone = src && jQuery.isArray(src) ? src : [];
75                     } else {
76                         clone = src && jQuery.isPlainObject(src) ? src : {};
77                     }
78 
79                     // Never move original objects, clone them
80                     // 遞歸
81                     target[name] = jQuery.extend(deep, clone, copy);
82 
83                     // Don't bring in undefined values
84                     // 最終都會到這條分支
85                     // 簡單的值覆蓋
86                 } else if (copy !== undefined) {
87                     target[name] = copy;
88                 }
89             }
90         }
91     }
92 
93     // Return the modified object
94     // 返回新的 target
95     // 如果 i < length ,是直接返回沒經過處理的 target,也就是 arguments[0]
96     // 也就是如果不傳需要覆蓋的源,調用 $.extend 其實是增加 jQuery 的靜態方法
97     return target;
98 };
View Code

最后做一個模擬JQuery Demo供大家學習

 1 (function (window, undefined) {
 2     var jQuery = function () {
 3         return new jQuery.fn.init();
 4     };
 5     jQuery.fn = jQuery.prototype = {
 6         add: function () { console.log("add"); },
 7         remove: function () { console.log("remove"); },
 8         init: function () { console.log("init"); return this; }
 9     };
10     jQuery.fn.init.prototype = jQuery.fn;
11     //添加擴展(靜態、實例)方法【demo】
12     //傳入{methodName:function(){}}
13     jQuery.extend = jQuery.fn.extend = function (obj) {
14         for (var item in obj) {
15             this[item] = obj[item];
16         }
17     }
18     window.jQuery = window.$ = jQuery;
19 })(window)
1 $.extend({ staticMethod: function () { console.log("staticMethod"); } });
2 $.fn.extend({ instanceMethod: function () { console.log("instanceMethod"); } });
3 $.staticMethod();
4 $().instanceMethod();

輸出:

 

借鑒:jQuery v1.10.2 源碼注解


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM