jquery內部實現原理分析


我們經常用jquery的選擇器,甚至爲jquery寫插件寫擴展,今天來討論一下jquery內部的實現原理(基於jquery-1.11.1.js)。

一、關於window.$和window.jQuery

其實在jquery中最開始只定義了一個jQuery局部變量,就是一個函數對象,即如下的形式

jQuery=function(selector, context){
....
}

在jquery的末尾位置處,纔將jQuery局部變量賦值給了window.$和window.jQuery,即window.$ = window.jQuery = jQuery

這裏需要說明的是,jQuery指向的匿名函數對象如果僅僅從形式上看,它甚至不一定返回一個對象,因爲javascript是動態語言具有函數式編程的特性,可以返回函數(雖然在javascript中函數也是對象但是函數對象和實例對象是不一樣的),或者以函數作爲參數,當然也可以返回對象和基本類型。

jQuery是如何具有大量函數特性,並且極易擴展的特性等等,要想了解需要對jQuery中原型鏈式關係進行後續分析。

二、關於jQuery.fn和jQuery.prototype

其實在jquery中jQuery.fn和jQuery.prototype是等價的,他們也是一個對象字面量

jQuery.fn = jQuery.prototype={
    ....
}
對象字面量其實也是隱式的調用了new Object(),所以jQuery的原型對象其實也是Object.prototype

三、關於jquery選擇器

jquery中經常用到選擇器,例如$("#id").css()等等,觀察這種形式,我們直觀上自己實現的時候可能會是這樣的形式,

jq = new $("#id")
jq.css()

但是jquery的選擇器使用的時候並不需要用戶去實例化jquery對象,並沒有new關鍵詞。其實jquery利用了閉包的方式,在$("#id")函數調用的時候,內部會調用new去實例化另一個函數對象。看起來可能是這個樣子

window.$ = window.jQuery=function(){
    return new some_function();
}

閉包就是爲了免除用戶去寫 new jQuery,那麼你裏面爲什麼是some_function而不是jQuery,這是因爲外面已經是jQuery了,如果裏面也是jQuery,會造成死循環調用,導致棧溢出。

上面的思路否決了,some_function到底是什麼呢?jQuery擁有的那麼多方法是放在哪裏的?

因爲jQuery是一個函數對象,如果在裏面添加一些方法是可以的,然後some_function.prototype=jQuery這樣可以嗎?實際上,如果只是要實現選擇器的功能是可以的,代碼可能如下:

window.$ = window.jQuery= function(){
   
}
window.jQuery.max = function(){
}
window.jQuery.map = function(data,index){
}

但是jquery並沒有像上面的代碼這樣做,jquery寫了一個字面量對象fn,它裏面包含了各種函數,例如each和map、grep等等,這樣讓選擇器和jQuery本身獨立開來,這樣以來我們很容易能夠定義一些全局的函數,例如常用的$.post, $.get,$.getJSON,$.min等等。

既然用字面量對象fn的方式是很有好處的,那麼是不是some_function的prototype指向這個字面量對象fn就可以,其實確實是可以的,不過jquery就不是隨便指定的some_function,而是在字面量對象fn中放置了一個init函數,並且 設置了jQuery.fn.init.prototype = jQuery.fn = jQuery.prototype

這樣保證了通過$("#id")取得的init的實例也擁有了fn的大量函數和特性,並且代碼更加簡潔(不需要增加一個和fn和jquery本身沒有關係的some_function)。

四、進一步的思考

其實,可能瞭解了這些會思考,爲什麼一定要設置jQuery.prototype = fn字面量對象,設置jQuery.fn = (fn字面量)對象就足夠了啊?

其實確實只要Init的prototype是fn字面量對象就滿足了選擇器始終擁有fn的大量函數和特性。 其實在jQuery中其實從始至終在選擇器使用上也好,在一邊的jQuery.max類似的函數調用也好,都沒有實例化jQuery對象,在選擇器使用的時候也只是實例化了jQuery.fn.init這樣使得實例化速度很快(因爲jQuery函數很大因爲隨着功能的增多)。對於爲什麼要jQuery.fn = jQuery.prototype = fn對象字面量,確實是一個值得思考的問題?其實應該反過來想,jQuery.prototype是定義的字面量,init.prototype = jQuery.prototype,這樣就可以達到選擇器所有需要的功能,但是每次如果擴展函數和方法都要寫很長的”prototype“會不顯得不美觀,爲了簡潔,引入了.fn別名。這樣一切就順理成章了。

五、建議


去官網http://jquery.com/下載一份Jquery.js來閱讀,肯定會收益匪淺。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章