立即執行函數(Immediate Functions)
立即執行函數模式是一種語法,可以讓你的函數在定義後立即被執行,比如:
- (function () {
- alert('watch out!');
- }());
立即執行函數(immediate function)術語不是在ECMAScript標準中定義的,但它很短有助於描述和討論模式;
這種模式有一些幾部分組成:
- 使用函數表達式定義一個函數(函數聲明不能起作用)
- 在結尾加上一對括號,讓函數立即被執行
- 將整個函數包裹在一對括號中(只有在你不將函數賦值給一個變量的時候才需要)
- (function () {
- alert('watch out!');
- })();
考慮一下下面這種常見的場景:
你的代碼在頁面代碼加載完成之後,不得不執行一些設置工作,比如附加時間處理器,創建對象等等,
所有的這些工作只需要執行一次,所以沒有理由創建一個可複用的命名的函數,
但這些代碼也需要一些臨時的變量,但初始化過程結束後,就再也不會被用到了,
所以將這些變量作爲全局變量不是個好主意,所以我們需要立即執行函數——去將我們所有的代碼包裹在它的局部作用域中,不會讓任何變量泄露成全局變量;
- (function() {
- var days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
- today = new Date(),
- msg = 'Today is ' + days[today.getDay()] + ', ' + today.getDate();
- alert(msg);
- } ()); // "Today is Fri, 13"
立即執行函數的參數(Parameters of an Immediate Function)
你也可以給立即執行函數傳遞參數,就像下面的例子一樣:
- // prints:
- // I met Joe Black on Fri Aug 13 2010 23:26:59 GMT-0800 (PST)
- (function(who, when) {
- console.log("I met " + who + " on " + when);
- } ("Joe Black", new Date()));
- (function (global) {
- // access the global object via `global`
- }(this));
立即執行函數的返回值(Returned Values from Immediate Functions)
就像其它任何函數一樣,一個立即執行函數也能返回值並且可以複製給其它變量:
- var result = (function () {
- return 2 + 2;
- }());
- var result = function () {
- return 2 + 2;
- }();
如果沒有注意到函數結束的括號,一些人可能就會認爲result指向一個函數;
實際上result指向立即執行函數的返回值,在這種情況下是數字 4 。
還有另一種語法可以實現相同的功能:
- var result = (function () {
- return 2 + 2;
- })();
但是除了基本類型值,立即執行函數也能返回任何類型的值,包括其它的函數;
那麼,你可以利用立即執行函數的作用域爲返回的內部函數私下裏存儲一些數據。
在接下來的例子中,立即執行函數的返回值是一個函數——被賦值給了變量getResult,這個函數簡單的返回了res的值,這個值事先被計算並被儲存在立即執行函數的閉包中:
立即執行函數也可以用來定義對象的屬性;
- var getResult = (function() {
- var res = 2 + 2;
- return function() {
- return res;
- };
- } ());
假如,你需要定義一個很可能在對象生命週期中都不會改變的屬性,但在你定義之前,你需要做一下工作去計算出正確的值;
你可以使用立即執行函數去封裝這些工作,並且立即執行函數的返回值將會成爲屬性的值,下面的代碼:
在這個例子中,o.message是一個字符串類型的屬性,不是一個函數,但它需要一個函數在腳本被載入時被執行並幫忙定義屬性。
- var o = {
- message: (function() {
- var who = "me",
- what = "call";
- return what + " " + who;
- } ()),
- getMsg: function() {
- return this.message;
- }
- };
- // usage
- o.getMsg(); // "call me"
- o.message; // "call me"
你定義的所有變量都會成員立即執行函數的局部變量,所以你不用擔心這些臨時變量會污染全局空間。
這種模式經常被使用在書籤工具(bookmarklets)中,因爲書籤工具在任何頁面上運行並且保持全局命名空間乾淨是非常必要的;
這種模式也可以讓你將獨立的功能封裝在自包含模塊中(self-contained modules)。
假如你的頁面是穩定的並且在沒有JavaScript情況下能正常工作,然後本着逐步加強的想法,你加入了一些代碼加強頁面某個方面;
你可以將這些代碼封裝進一個立即執行函數中,並且確保頁面沒有它的情況下也能正常工作。
然後你可以添加更多的加強模塊,移除它們,單獨測試它們,允許用戶去禁用它們等等。
你可以使用下面的模板去定義一個函數模塊,讓我們叫它module1:
- // module1 defined in module1.js
- (function () {
- // all the module 1 code ...
- }());