如果你也曾經自認為懂 JavaScript,建議您看看你其實並不懂JavaScript,評量看看您是否真的了解,通常看過之後大部分人會覺得自己知道,但我必須說除非你確認你有開發並應用到相關的知識,不然只是從書上看過並不代表你真的了解!尤其 JavaScript 還有很多出乎正常邏輯外的運算結果!一起來精進 JavaScript 吧。 這次就讓我們先從 jQuery 的進入點來看吧:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* ! | |
* Partial jQuery, extracted from | |
* jQuery JavaScript Library v1.7.2 | |
*/ | |
(function( window, undefined ) { | |
// Use the correct document accordingly with window argument (sandbox) | |
var document = window.document, | |
navigator = window.navigator; | |
... skip .... | |
})( window ); |
function(window, undefined){} 這定義了一個 Anonymous function
之後透過括號 () 包住 Anonymous function: (function(window, undefined){}) 取得 evaluate 過的 Anonymous function 再透過 () 去執行 Anonymous function
(function(window, undefined){})();
這邊有個重點是一定要先用 () 包住 Anonymous function ,否則會得到 syntax error。 Paul Irish 的 10 things I learned from jQuery 影片裡面關於這一點似乎說錯,他說技術上這一點是 optional ,但很明顯的不是如此。
不過另外他提到的 Facebook 的 source code 裡面有看到一些相同作用但不同語法的方式是:
!function(window, undefined){}(); 或 +function(window, undefined){}();
這部份就是正確的,基本上都只是需要讓 Anonymous 先產生定義,再透過後面的 () 執行它。
到目前為止僅是語法的部分,但在這之外 jQuery 使用這 self invoking anonymous function 的 pattern 一定有其意義。最重要的意義我想應該就在於 John Resig 自己的書 Secrets of the JavaScript Ninja 裡面所提到的 Library Wrapping。透過 Anonymous function 的 local scope 將 library 本身定義的 variables 以及 functions 限制在 local scope 裡面,這麼一來不會影響全域的命名空間,同時也避免 jQuery 自己的變數以及其他定義被外界影響。
了解語意之後,再來看看 jQuery Anonymous function 的參數 window 以及 undefined 的意義。第一個參數 window 很容易理解,在呼叫 Anonymous function 的時候傳入 window,因此而將 window 從 global 變數轉換成在 local scope 的一個 reference。雖然說不傳也可以直接存取 window 這個變數,但這邊轉換成 local scope 的 window reference 之後可以提升一些效能。原理大概是在 JavaScript 裡面存取變數的時候會先在 local scope 找, 找不到的話再往上找 global scope。這邊的作法就會讓 window 的存取少了一層,因此可以增進效能。不過那也是因為 jQuery 會大量用到 window,如果你的 code 裡面沒有大量用到應該也是不用這樣做 :)
至於 undefined 這個參數,首先第一個特別的點是在呼叫的時候沒有傳第二個參數,所以透過 JavaScript 的語法讓第二個參數 "underfined" 帶入 window.undefined。這樣做的原因我聽過兩個,第一個是說由於 undefined 是一個 global 變數,有可能被改掉,所以必須透過這個方式綁定 undefined 的值。這樣一來就不怕 undefined 的值被突然改掉了。第二個說法是,有些瀏覽器的 undefined 不叫 undefined,所以透過這個方法可以強制讓 undefined 都是 undefined。基本上兩個方法都合理,但我也都有點存疑。第一個說法讓我存疑的是在於那為什麼就不管其他的 global variables?而只處理 undefined?也許是因為 jQuery 真的只用到 undefined 吧。再來是,我實驗了把 window.undefined 的值改掉,結果發現改不掉,看來現在瀏覽器(筆者使用 Chrome 19.0.1084.56 測試)很聰明的會保護一些特別的值。所以目前就我看起來真不是理由 XD 第二個說法存疑的點是真的有瀏覽器沒有支援 window.undefined ? 也許真的有,但至少我還沒遇過。
好的, jQuery 原始碼解讀第一趴就先到這裡了。 待續...
參考:
jQuery, John Resig
10 things I learned from jQuery source, Paul Irish
Speed up your JavaScript, Nicholas C. Zakas
Secrets of the JavaScript Ninja, Jogn Resig
thx for sharing.
回覆刪除