1.自執行函式表示式

kyo4311發表於2015-07-06

當我要寫一個外掛了,首先就會敲這樣一段程式碼:

(function(){

}());

對,就是這個自執行函式,有的人叫它立即呼叫函式,還有更高大的叫法:立即呼叫的函式表示式。不管怎麼樣,他是自己會執行的。

為什麼要這樣寫呢?
因為這樣子寫有一個好處,減少全域性變數的汙染。那好吧!我們就多幾一點程式碼來試一下。

(function(){
   var a = 1;
}());

alert(a); //ReferenceError: a is not defined

很明顯,我們定義的變數a,在外面已經訪問不到了。a就是一個私有的變數,所以不管裡面定義多少變數,也不會外面的變數衝突了,那就放心大膽的寫吧!

為什麼這樣子就私有了呢?
1.因為在JavaScript裡,任何function在執行的時候都會建立一個執行上下文;
2.function裡面宣告的變數和function有可能只在該function內部訪問;
所以我們就利用了這個執行上下文,來建立私有變數或私有子function。

為什麼會是這樣子寫呢? 首先我們將就最簡單的例子看起:

//定義個function
var foo = function () {
    //code  
};

//使用小括號,即可以執行
foo();

這樣子,我們就發現,原來加小括號,在javascript裡,還有一個意思,就是執行一個function。那麼我們會不會很自然的去改一下程式碼,變成下面這樣子呢?

var foo = function () {
    console.log(1);
}();

不錯,還是可以執行的,接著改造如下:

function () {
    console.log(1);
}();

經過改造之後,徹底的不能玩耍了,原因何在?
因為在解析器解析全域性的function或者function內部function關鍵字的時候,預設是認為function宣告,而不是function表示式,如果你不顯示告訴編譯器,它預設會宣告成一個缺少名字的function,並且丟擲一個語法錯誤資訊,因為function宣告需要一個名字。

不是說加一個名字就好的嗎?

function foo() {
    console.log(1);
}();

結果還是玩不了,因為他只是一個語句,分組操作符需要包含表示式,所以還是報錯。什麼是語句什麼是表示式這裡就細講了。有興趣的同學請參考:http://www.cnblogs.com/slowsoul/archive/2013/01/21/2870310.html

也許我是亂敲的程式碼嗎,不小心在括號裡面多敲了一個1,程式碼變成這樣子了。

function foo() {
    console.log(1);
}(1);

我們神奇的發現,程式碼不報錯了,雖然不報錯了,但是並不是我們想要的結果,實際上他真面目是這樣子的。

//宣告一個函式
function foo() {
    console.log(1);
}

//一個表示式
(1);

他是兩段程式碼,相互沒有什麼關係。迴歸語句和表示式,我們是不想到,只要把語名變成表示式,他就不會報錯了呢?是的,變成表示式就不會報錯。所以我們在function外面加一個()他就變成了一個表示式了。程式碼就變成下面這樣子了。

(function foo() {
    console.log(1);
});

好的,終於不報錯了,接下來也細說一下這段程式碼。
1.因為JavaScript裡括弧()裡面不能包含語句,程式碼解析成function表示式,而不是function宣告。
2.()裡面的值,就是一個function,就像(1)一樣,把1想像成function吧。

終於看到了曙光,我們就來完成最後一步吧!

(function foo() {
    console.log(1);
}());

加上一個括號,就變成了我開始寫的那樣子的一段程式碼。現在我們應該最知道他叫什麼了吧!他叫自執行函式表示式或是立即呼叫的函式表示式。

當找到一個方法之後,人們總是會探索別外的方法,我們只能這樣子寫嗎?不是的,我們還可以這樣子寫。

(function foo() {
    console.log(1);
})();

有人會問,哪種方法更好,事實上沒有多大的區別,而我個人偏好把小括號放裡面的那種方式,還有更多的玩法,只要把他變成表示式就行了。

// 由於括弧()和JS的&&,異或,逗號等操作符是在函式表示式和函式宣告上消除歧義的
// 所以一旦解析器知道其中一個已經是表示式了,其它的也都預設為表示式了
// 不過,請注意下一章節的內容解釋

var i = function () { return 10; } ();
true && function () { /* code */ } ();
0, function () { /* code */ } ();

// 如果你不在意返回值,或者不怕難以閱讀
// 你甚至可以在function前面加一元操作符號

!function () { /* code */ } ();
~function () { /* code */ } ();
-function () { /* code */ } ();
+function () { /* code */ } ();

// 還有一個情況,使用new關鍵字,也可以用,但我不確定它的效率
new function () { /* code */ }
new function () { /* code */ } () // 如果需要傳遞引數,只需要加上括弧()

事實有這麼多的方案可以讓一個function自執行,為何所有開發都要用()呢?原因也是很簡單,這樣子寫,可以讓程式碼更容易閱讀。

相關文章