當即執行函數模式是一種語法,可讓你的函數在定義後當即被執行,好比:javascript
[javascript] view plain copyjava
(function () { 瀏覽器
alert('watch out!'); 閉包
}()); 函數
這種模式本質上就是函數表達式(命名的或者匿名的),在建立後當即執行;工具
當即執行函數(immediate function)術語不是在ECMAScript標準中定義的,但它很短有助於描述和討論模式;測試
這種模式有一些幾部分組成:this
使用函數表達式定義一個函數(函數聲明不能起做用)spa
在結尾加上一對括號,讓函數當即被執行.net
將整個函數包裹在一對括號中(只有在你不將函數賦值給一個變量的時候才須要)
下面這種可選的語法形式也是很常見的(注意結尾的一對括號),但JSLint趨向於第一種:
[javascript] view plain copy
(function () {
alert('watch out!');
})();
這種模式是很是有用的,由於它爲你初始化代碼提供了一個做用域的沙箱;
考慮一下下面這種常見的場景:
你的代碼在頁面代碼加載完成以後,不得不執行一些設置工做,好比附加時間處理器,建立對象等等,
全部的這些工做只須要執行一次,因此沒有理由建立一個可複用的命名的函數,
但這些代碼也須要一些臨時的變量,但初始化過程結束後,就不再會被用到了,
因此將這些變量做爲全局變量不是個好主意,因此咱們須要當即執行函數——去將咱們全部的代碼包裹在它的局部做用域中,不會讓任何變量泄露成全局變量;
[javascript] view plain copy
(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都將成爲全局變量,初始化代碼的遺留產物。
你也能夠給當即執行函數傳遞參數,就像下面的例子同樣:
[javascript] view plain copy
// 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也能夠被訪問到:這種方式可讓代碼在環境(除了瀏覽器)中更加通用:
[javascript] view plain copy
(function (global) {
// access the global object via `global`
}(this));
記住:一般你不該該給當即執行函數傳遞太多的函數,由於它很快會成爲一個負擔——爲了理解代碼是如何工做的,你不得不常常上下滾動源代碼。
就像其它任何函數同樣,一個當即執行函數也能返回值而且能夠複製給其它變量:
[javascript] view plain copy
var result = (function () {
return 2 + 2;
}());
另一種實現相同的功能的方法是省略包裹函數的括號,由於當你將當即執行函數的返回值賦值給一個變量時它們不是必需的;
[javascript] view plain copy
var result = function () {
return 2 + 2;
}();
這種語法是很是簡單的,但它可能看起來有點使人誤導;
若是沒有注意到函數結束的括號,一些人可能就會認爲result指向一個函數;
實際上result指向當即執行函數的返回值,在這種狀況下是數字 4 。
還有另外一種語法能夠實現相同的功能:
[javascript] view plain copy
var result = (function () {
return 2 + 2;
})();
在前面的例子中返回一個基本類型的整數做爲當即執行函數的返回值;
可是除了基本類型值,當即執行函數也能返回任何類型的值,包括其它的函數;
那麼,你能夠利用當即執行函數的做用域爲返回的內部函數私下裏存儲一些數據。
在接下來的例子中,當即執行函數的返回值是一個函數——被賦值給了變量getResult,這個函數簡單的返回了res的值,這個值事先被計算並被儲存在當即執行函數的閉包中:
[javascript] view plain copy
var getResult = (function() {
var res = 2 + 2;
return function() {
return res;
};
} ());
當即執行函數也能夠用來定義對象的屬性;
假如,你須要定義一個極可能在對象生命週期中都不會改變的屬性,但在你定義以前,你須要作一下工做去計算出正確的值;
你可使用當即執行函數去封裝這些工做,而且當即執行函數的返回值將會成爲屬性的值,下面的代碼:
[javascript] view plain copy
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是一個字符串類型的屬性,不是一個函數,但它須要一個函數在腳本被載入時被執行並幫忙定義屬性。
當即執行函數模式被普遍使用,它能夠幫你封裝大量的工做而不會在背後遺留任何全局變量。
你定義的全部變量都會成員當即執行函數的局部變量,因此你不用擔憂這些臨時變量會污染全局空間。
這種模式常常被使用在書籤工具(bookmarklets)中,由於書籤工具在任何頁面上運行而且保持全局命名空間乾淨是很是必要的;
這種模式也可讓你將獨立的功能封裝在自包含模塊中(self-contained modules)。
假如你的頁面是穩定的而且在沒有JavaScript狀況下能正常工做,而後本着逐步增強的想法,你加入了一些代碼增強頁面某個方面;
你能夠將這些代碼封裝進一個當即執行函數中,而且確保頁面沒有它的狀況下也能正常工做。
而後你能夠添加更多的增強模塊,移除它們,單獨測試它們,容許用戶去禁用它們等等。
你可使用下面的模板去定義一個函數模塊,讓咱們叫它module1:
[javascript] view plain copy
// module1 defined in module1.js
(function () {
// all the module 1 code ...
}());