IIFE (Imdiately Invoked Function Expression 立即執行的函式表示式)

風暴阿呆發表於2017-12-14

函式宣告

函式宣告時必須有函式名

function fn(){};
複製程式碼

函式表示式

函式表示式中的函式可以為匿名函式,也可以有函式名,但是該函式不能直接使用,只能通過表示式左邊的變數 fn 來呼叫

var fn = function(){};
複製程式碼

看看兩者區別

function a(){
    console.log("函式宣告");
}
var b = function(){
    console.log("函式表示式"); 
}
a();   //函式申明
b();   //函式表示式
複製程式碼
a();   //函式宣告
b();   //報錯
function a(){
    console.log("函式宣告");
}
var b = function(){
    console.log("函式表示式"); 
}
複製程式碼

為什麼會有這樣的結果?
原因: function a(){} 為函式宣告,程式執行前就已經存在;var b = function(){} 為函式表示式,屬於按順序執行,所以 b() 會報錯

進入IIFE (立即執行的函式表示式)

在ES5中,是沒有塊級作用域的概念的;我們主要通過匿名函式的方式來塊級作用域。
用作塊級作用域(私有作用域)的匿名函式的語法:

(function() { //此處是塊級(私有)作用域 })();

!function () { //此處是塊級(私有)作用域  } ();   
~function () { //此處是塊級(私有)作用域  } ();   
-function () { //此處是塊級(私有)作用域  } ();   
+function () { //此處是塊級(私有)作用域  } ();   

//這些都是立即執行的函式表示式的寫法
//定義並立即呼叫了一個匿名函式。將函式宣告包含在一對圓括號中,表示它實際上是一個函式表示式。
複製程式碼
IIFE 寫法的產生:
var a = function() { console.log("IIFE 寫法的產生"); };
a();   //IIFE 寫法的產生 
//我們將一個匿名函式賦值給了一個全域性變數a,然後呼叫了這個函式
複製程式碼
衍生出 IIFE 寫法
(function(){
    console.log("這是一個立即執行的函式");
})();
//第一個圓括號:將匿名函式轉換為函式表示式
//第二個圓括號:立即執行匿名函式(當然,你也可以設定一個函式名)
複製程式碼

總結: 1. 建立塊級(私有)作用域,避免了向全域性作用域中新增變數和函式,因此也避免了多人開發中全域性變數和函式的命名衝突
2.IIFE中定義的任何變數和函式,都會在執行結束時被銷燬。這種做法可以減少閉包占用的記憶體問題,因為沒有指向匿名函式的引用。只要函式執行完畢,就可以立即銷燬其作用域鏈

常用例項

預期: 使用 setTimeout 迴圈輸出 0 1 2 3 4 5

for(var i = 0; i <= 5; i++){
    setTimeout(function timer(){
        console.log(i);
    },  i*1000);
}
//結果:1秒內輸出6個6
複製程式碼

原因: 超時的回撥函式都將在迴圈完成之後立即執行。
解決方法:

方法一:
for(var i = 0; i <= 5; i++){
    (function(){
        var j = i;
        setTimeout(function timer(){
            console.log(j);
        }, j*1000)
    })();
}
//結果: 0 1 2 3 4 5
複製程式碼
方法二:
for(var i = 0; i <= 5; i++){
    (function(j){
        setTimeout(function timer(){
            console.log(j);
        }, j*1000)
    })(i);
}
//結果: 0 1 2 3 4 5
複製程式碼

IIFE 為每次迭代建立了新的作用域,這給了超時回撥函式一個機會在每次迭代時閉包一個新的作用域。


相關文章