JavaScript學習筆記(十四) 立即執行函數

立即執行函數(Immediate Functions)

立即執行函數模式是一種語法,可以讓你的函數在定義後立即被執行,比如:
(function () {
    alert('watch out!');
}());
這種模式本質上就是函數表達式(命名的或者匿名的),在創建後立即執行;
立即執行函數(immediate function)術語不是在ECMAScript標準中定義的,但它很短有助於描述和討論模式;

這種模式有一些幾部分組成:
  • 使用函數表達式定義一個函數(函數聲明不能起作用)
  • 在結尾加上一對括號,讓函數立即被執行
  • 將整個函數包裹在一對括號中(只有在你不將函數賦值給一個變量的時候才需要)
下面這種可選的語法形式也是很常見的(注意結尾的一對括號),但JSLint趨向於第一種:
(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"
如果代碼沒有被包裹在立即執行函數中,那麼局部變量days,today和msg都將成爲全局變量,初始化代碼的遺留產物。

立即執行函數的參數(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()));
通常,全局變量被作爲一個參數傳遞給立即執行參數,這樣它在函數內部不使用window也可以被訪問到:這種方式可以讓代碼在環境(除了瀏覽器)中更加通用:
(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;
    };
} ());
立即執行函數也可以用來定義對象的屬性;
假如,你需要定義一個很可能在對象生命週期中都不會改變的屬性,但在你定義之前,你需要做一下工作去計算出正確的值;
你可以使用立即執行函數去封裝這些工作,並且立即執行函數的返回值將會成爲屬性的值,下面的代碼:
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"
在這個例子中,o.message是一個字符串類型的屬性,不是一個函數,但它需要一個函數在腳本被載入時被執行並幫忙定義屬性。

好處和用法(Benefits and Usage)

立即執行函數模式被廣泛使用,它可以幫你封裝大量的工作而不會在背後遺留任何全局變量。
你定義的所有變量都會成員立即執行函數的局部變量,所以你不用擔心這些臨時變量會污染全局空間。

這種模式經常被使用在書籤工具(bookmarklets)中,因爲書籤工具在任何頁面上運行並且保持全局命名空間乾淨是非常必要的;

這種模式也可以讓你將獨立的功能封裝在自包含模塊中(self-contained modules)。
假如你的頁面是穩定的並且在沒有JavaScript情況下能正常工作,然後本着逐步加強的想法,你加入了一些代碼加強頁面某個方面;
你可以將這些代碼封裝進一個立即執行函數中,並且確保頁面沒有它的情況下也能正常工作。
然後你可以添加更多的加強模塊,移除它們,單獨測試它們,允許用戶去禁用它們等等。

你可以使用下面的模板去定義一個函數模塊,讓我們叫它module1:
// module1 defined in module1.js
(function () {
// all the module 1 code ...
}());












發佈了4 篇原創文章 · 獲贊 27 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章