天天看點

jQuery:了解$(document).ready()的特殊寫法

看書時注意到下面兩條語句的功效是相同的,

這個特殊寫法就是用$()代替$(document).ready(),類似于(有差異)window.onload彈出個視窗:

jQuery:了解$(document).ready()的特殊寫法

檢視jQuery1.8.3源代碼,是這樣封裝的:

下列語句把封裝在内部的jQuery先賦給window.$,緊接着再賦給window.jQuery。這意味着在實際使用時window.$和window.jQuery是一回事。因為$這個符号隻有1個字母,比jQuery短,是以更常用一些,但要注意到$非jQuery所獨有,節約字母的代價是增加了命名沖突的風險。

下面是jQuery的初始化語句(注意到此時函數并未執行):

找到jQuery.fn的定義,這是一個對象,其中有一個叫init的函數元素: 

繼續下去,init中有一段邏輯:

暈了暈了,rootjQuery的定義又回到了jQuery:

有點遞歸的意思了,嗯,就是遞歸。jQuery不僅僅是一個函數,而且還是一個遞歸函數。

如果調用jQuery時輸入的是一個函數,例如文章開頭提到的:

那麼這個函數就會走到rootjQuery那裡,再回到jQuery,執行jQuery(document).ready。而$與jQuery是一回事,這樣就解釋了$(inputFunction)可以代替$(document).ready(inputFunction)。

現在還不想結束此文,我的問題是$(document)做了什麼?嗯,還是要進入到jQuery.fn.init,确認存在nodeType屬性,達到“Handle $(DOMElement)”的目的。怎麼Handle呢?具體就是把輸入參數(此時為document)指派給this的context屬性,然後再傳回this。也就是說,$(document)執行完了傳回的還是jQuery,但是情況發生了變化,具體就是context屬性指向了輸入參數(此時為document)。暫時還不明白繞這麼大個圈子為context(上下文)屬性指派有何意義?

接下去的問題可能會是$(document).ready和window.onload的差別?提取ready函數的定義如下:

閱讀代碼探究promise是有點暈啊,想到自己的iJs工具包了,列印jQuery.ready.promise()如下:

    [Object] jQuery.ready.promise()

        |--[function] always

        |--[function] done

        |--[function] fail

        |--[function] pipe

        |--[function] progress

        |--[function] promise

        |--[function] state

        |--[function] then

進一步列印整理done函數代碼如下(這下徹底暈了~~):

好在代碼不長,看起來關鍵就在于fire函數了。嗯,找回一絲清醒了。在上面的done函數裡面可以注意到使用了預設的arguments變量,将注入的函數push到了list數組。下面是fire函數:

可以看到代碼中對list數組裡面使用了apply。用iJs包調試可發現data[0]就是document對象,也就是說,調用$(myFunction)的結果是在document對象上執行了myFunction。因為list是個數組,是以也就不難了解$()其實是多次輸入,一次執行。

最後,回過頭來閱讀promise源代碼,關于$()輸入函數的執行時機的秘密就在這裡了:

從代碼的注釋中可以看到這段代碼在消除bug的過程中還是頗費了些心思的。檢視其中一個網址http://bugs.jquery.com/ticket/12282#comment:15,是關于IE9/10的一個bug(document ready is fired too early on IE 9/10),好在已經解決。

繞了這麼多彎子,整個事情看起來就是這樣,如果每一個浏覽器都能有document.readyState === "complete",就簡單了。再看到$(),要感謝編寫jQuery的大神們(以及其他類似架構的大神們),是他們的努力,讓世界變得完美。