關於立即調用的函數表達式(IIFE)

  • 2019 年 10 月 6 日
  • 筆記

在 JavaScript 中,圓括號 () 是一種運算符,跟在函數名之後,表示調用該函數。比如,print() 就表示調用 print 函數

有時,我們需要在定義函數之後,立即調用該函數,例如:

function(){ /* code */ }();  // SyntaxError: Unexpected token (

以上代碼出現了語法錯誤 原因是,function 這個關鍵字即可以當作語句,也可以當作表達式

// 語句  function f() {}    // 表達式  var f = function f() {}

其中,JavaScript 引擎規定,如果 function 關鍵字出現在行首,一律解釋成語句

因此,上面錯誤的代碼被認為這一段都是函數的定義,不應該以圓括號結尾,所以就報錯了

解決方法就是不要讓 function 出現在行首,讓引擎將其理解成一個表達式

最簡單的處理,就是將其放在一個圓括號裏面

// 解決方式一  (function(){ /* code */ }());    // 解決方式二  (function(){ /* code */ })();

上面兩種寫法都是以圓括號開頭,引擎就會認為後面跟的是一個表示式,而不是函數定義語句,所以就避免了錯誤

這就叫做「立即調用的函數表達式」(Immediately-Invoked Function Expression),簡稱 IIFE

注意,上面兩種寫法最後的分號都是必須的。如果省略分號,遇到連着兩個 IIFE,可能就會報錯

// 報錯  (function(){ /* code */ }())  (function(){ /* code */ }())

上面代碼的兩行之間沒有分號,JavaScript 會將它們連在一起解釋,將第二行解釋為第一行的參數

推而廣之,任何讓解釋器以表達式來處理函數定義的方法,都能產生同樣的效果,比如下面三種寫法

// 寫法一  var i = function(){ return 10; }();    // 寫法二  true && function(){ /* code */ }();    // 寫法三  0, function(){ /* code */ }();

甚至像下面這樣寫,也是可以的。

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

通常情況下,只對匿名函數使用 IIFE

它的目的有兩個:一是不必為函數命名,避免了污染全局變量;

二是 IIFE 內部形成了一個單獨的作用域,可以封裝一些外部無法讀取的私有變量。

// 寫法一  var tmp = newData;  processData(tmp);  storeData(tmp);    // 寫法二  (function () {  var tmp = newData;  processData(tmp);  storeData(tmp);  }());

上面代碼中,寫法二比寫法一更好,因為完全避免了污染全局變量