天天看點

jQuery技術内幕:深入解析jQuery架構設計與實作原理. 1.3 自調用匿名函數

<b>1.3 自調用匿名函數</b>

從代碼清單1-1中還可以看到,jquery的所有代碼都被包裹在了一個立即執行的匿名函數表達式中,這種代碼結構稱為“自調用匿名函數”。當浏覽器加載完jquery檔案後,自調用匿名函數會立即開始執行,初始化jquery的各個子產品。相關代碼如下所示:

(function( window, undefined ) {

var jquery = ...

   //

...

window.jquery = window.$ = jquery;

})(window);

上面這段代碼涉及一些javascript基礎知識和編碼習慣,下面以提問的方式來逐一分析。

1)為什麼要建立這樣一個自調用匿名函數?

通過建立一個自調用匿名函數,建立了一個特殊的函數作用域,該作用域中的代碼不會和已有的同名函數、方法和變量以及第三方庫沖突。由于jquery會被應用在成千上萬的javascript程式中,是以必須確定jquery的代碼不會受到其他代碼的幹擾,并且jquery不能破壞和污染全局變量以至于影響到其他代碼。這一點是任何一個javascript庫和架構所必須具備的功能。

注意,在這個自調用匿名函數的最後,通過手動把變量jquery添加到window對象上,明确地使變量jquery成為公開的全局變量,而其他的部分将是私有的。

另外,自調用匿名函數還可以有兩種等價的寫法,如下所示(注意加了底紋的圓括号的位置):

// 寫法1(常見寫法,也是

jquery 所采用的)

( function() {

} )();

// 寫法2

}() );

// 寫法3

!function() {

}();

2)為什麼要為自調用匿名函數設定參數window,并傳入window對象?

通過傳入window對象,可以使window對象變為局部變量(即把函數參數作為局部變量使用),這樣當在jquery代碼塊中通路window對象時,不需要将作用域鍊回退到頂層作用域,進而可以更快地通路window對象,這是原因之一;另外,将window對象作為參數傳入,可以在壓縮代碼時進行優化,在壓縮檔案jquery-1.7.1.min.js中可以看到下面的代碼:

(function(a,b){ ... })(window);

// 參數 window 被壓縮為 a,參數 undefined

被壓縮為 b

3)什麼要為自調用匿名函數設定參數undefined?

特殊值undefined是window對象的一個屬性,例如,執行下面的代碼将會彈出true:

alert( "undefined" in window );

// true

通過把參數undefined作為局部變量使用,但是又不傳入任何值,可以縮短查找undefined時的作用域鍊,并且可以在壓縮代碼時進行優化,如前面代碼所示,參數undefined會被壓縮為b。

另外,更重要的原因是,通過這種方式可以確定參數undefined的值是undefined,因為undefiend有可能會被重寫為新的值。可以用下面的代碼來嘗試修改undefined的值,在各浏覽器中的測試結果見表1-1。

undefined = "now it's defined";

alert( undefined );

表1-1  在浏覽器中嘗試修改

undefined 的值

浏 覽 器     測 試 結 果  結  論

ie 6.0、ie 7.0、ie 8.0     now it's defined        可以改變

ie 9.0、ie 10.0         undefined         不能改變

chrome 16.0.912.77        now it's defined        可以改變

chrome 17.0.963.56       undefined         不能改變

firefox 3.6.28          now it's defined        可以改變

firefox 4.0        undefined         不能改變

safari 4.0.2       now it's defined        可以改變

safari 4.0.4       undefined         不能改變

opera 11.52     now

it's defined        可以改變

opera 11.60     undefined         不能改變

4)注意到自調用匿名函數最後的分号(;)了嗎?

通常在javascript中,如果語句分别放置在不同的行中,則分号(;)是可選的,但是對于自調用匿名函數來說,在之前或之後省略分号都可能會引起文法錯誤。例如,執行下面的兩個例子,就會抛出異常。

例1 在下面的代碼中,如果自調用匿名函數的前一行末尾沒有加分号,則自調用匿名函數的第一對括号會被當作是函數調用。

var n = 1

( function(){} )()

// typeerror: number is not a function

例2 在下面的代碼中,如果未在第一個自調用匿名函數的末尾加分号,則下一行自調用匿名函數的第一對括号會被當作是函數調用。

// typeerror: undefined is not a function

是以,在使用自調用匿名函數時,最好不要省略自調用匿名函數之前和之後的分号。

繼續閱讀