在第一篇jQuery源碼分析中,簡單分析了jQuery對象的構造過程,里面提到了jQuery.fn、jQuery.prototype、jQuery.fn.init.prototype的關系。
jQuery構造器
jQuery使用非常方便,其中一個原因就是我們在調用的時候並不需要使用關鍵字new來創造一個jQeury對象,直接使用jQuery("#id")或$(".class")就可輕松得到一個新的jQuery對象。原因就是jQuery使用工廠方法,利用構造器創造一個新的jQuery對象並返回,省去了用戶的new操作。
一般構造器
1 var $ = jQuery = function() { 2 return new jQuery(); 3 } 4 jQuery.prototype = { 5 jquery: "1.11" 6 };
7 console($().jquery);
上面的代碼有些奇怪,因為一個構造器返回利用它自身創建了一個新的對象並返回,這樣形成了一個死循環,產生棧溢出的異常。因此,上面的代碼是錯誤的代碼。
返回原型方法 jQuery.fn.init
1 var $ = jQuery = function() { 2 return jQuery.fn.init(); 3 } 4 jQuery.fn = jQuery.prototype = { 5 init: function(){ 6 return this; 7 }, 8 jquery: "1.11" 9 } 10 console.log($().jquery); 11 console.log($()); // 將jQuery.prototype打印出來, Object { init: jQuery.prototype.init(), jquery: "1.11"}
雖然這個方法解決了嵌套為問題,也將jQuery的原型方法傳遞給了jQuery對象,但它是將一個完整的jQuery.prototype暴露處理,jQuery的任何對this關鍵字的操作,實際上就是直接在jQuery.prototype上進行操作,那么jQuery.fn的完整性很容易就被破壞了,jQuery對象之間也可能產生不可預估的影響。
1 console.log($().jquery); // 1.11 2 $().jquery = '2.1'; 3 console.log($().jquery); // 2.1
返回一個jQuery.fn.init對象
1 var $ = jQuery = function() { 2 return new jQuery.fn.init(); 3 } 4 jQuery.fn = jQuery.prototype = { 5 init: function(){ 6 this.num = 2015; 7 return this; 8 }, 9 jquery: "1.11" 10 } 11 12 console.log($().num); // 2015 13 console.log($().jquery); // undefined 14 console.log($()); // Object {num: 2015}
但此時問題來了,new jQuery.fn.init()所返回的新對象並沒有繼承jQuery.fn,因為jQuery.fn.init.prototype僅僅是指向了一個function對象的原型,並不包含jQuery.fn。這時,是徹底地將jQuery.fn給封鎖了起來。
讓jQuery.fn.init.prototype指向jQuery.fn
1 var $ = jQuery = function(x) { 2 return new jQuery.fn.init(x); 3 } 4 jQuery.fn = jQuery.prototype = { 5 init: function(x){ 6 this.num = x || 0; 7 return this; 8 }, 9 jquery: "1.11" 10 } 11 jQuery.fn.init.protoytpe = jQuery.fn; 12 13 console.log($(2015).num); // 2015 14 console.log($(2015).jquery); // 1.11 15 console.log($(2016).num); // 2016 16 console.log($(2016).__proto__); // Object { init: jQuery.prototype.init(), jquery: "1.11" }
顯然,jQuery.fn.init這個工廠方法完全奏效了,$()返回的每個對象,都擁有獨立的內部變量,也共享jQuery.fn上的公有方法和屬性。
總結
- jQuery.prototype,掛載jQuery對象的原型方法;
- jQuery.fn是jQuery.prototype的別名,標注jQuery.prototype的意義且縮短代碼書寫長度,避免混淆(像jQuery.prototype.init.prototype = jQuery.prototype這行代碼,能把人看昏了)方便使用;
- jQuery.fn.init.prototype,則是為了讓jQuery.fn.init這個工廠方法能夠繼承jQuery.fn上的原型方法。
參考書:朱印宏 《jQury內核詳解與實戰》