[JS] Function基本介紹-2
TL;DR
本篇介紹立即函式內容如下:
- 為什麼要使用立即函示
- 立即函示的特性
- 立即函示參數傳遞
- 立即函示回傳值
參考資料
- 呼叫函式時,到底有多少個參數 / 變數可供使用? | Casper
- JavaScript 一級函式 (First Class Functions) | Casper
相關連結
- 一級函式(First-class Function) | MDN
- IIFE | MDN
立即函式(IIFE)
如同字面上的意思,立即函式會在載入JS程式碼之後立刻執行。
立即函式具有以下幾個特性:
- 不可再次呼叫
- 可以限制變數作用域避免污染全域
基本範例
首先, 我們先從將傳統的函式轉換為立即函式的範例開始。
以下是一段我們定義好的函式,並且在定義之後馬上執行:
function foo() {
console.log('bar');
}
foo(); // bar
轉換為立即函式的方法有數種,以下分別介紹。執行結果完全相同。
• 型式一
將函式使用小括號包起來。並且在小括號結尾前方補上另一組小括號。
(function foo() {
console.log('bar');
}());
• 型式二
將函式使用小括號包起來。在小括號結尾後方補上另一組小括號。
(function foo() {
console.log('bar');
})();
特性介紹
• 無法再次呼叫
前面有介紹立即函式的特點為無法再次被呼叫,這是什麼意思呢?
讓我們用以下範例簡單示範這個概念:
(function IIFE() {
console.log('IIFE',IIFE);
})();
// IIFE ƒ IIFE() {
// console.log('IIFE',IIFE);
// }
執行結果圖示
目前看起來IIFE這個具名函式可以正確被調用。
但是!!當我們在立即函式外再次調用IIFE時則會出現錯誤:
(function IIFE() {
console.log('IIFE',IIFE);
})();
console.log(IIFE)
//執行結果如下:
// IIFE ƒ IIFE() {
// console.log('IIFE',IIFE);
// }
// Uncaught ReferenceError: IIFE is not defined
執行結果圖示
• 限制作用域
另一個使用IIFE的原因是因為,我們可以限制作用域,避免造成變數的衝突或覆蓋。
(function IIFE() {
console.log('IIFE1',IIFE);
})();
(function IIFE() {
console.log('IIFE2',IIFE);
})();
// IIFE1 ƒ IIFE() {
// console.log('IIFE1',IIFE);
// }
// IIFE2 ƒ IIFE() {
// console.log('IIFE2',IIFE);
// }
執行結果圖示
可以發現雖然我們定義了兩個具名函式都叫IIFE,但是因為是立即函式,所以就算Function名稱相同,也可以正確執行而不會產生錯誤。
當然內部的變數也都會被限制在該立即函式中。這麼一來就可以避免污染到全域的變數。
並且因為立即函式的名稱無法在外部再次呼叫,所以大部分狀況我們是不需要給予立即函式名稱的。
(function () {
console.log('立即函式');
})();
上方程式碼是可以正確執行的。
最後,我們來示範一下內部變數是否可以正確限制作用域:
(function(){
var Ming='小明';
console.log(Ming);
})();
// 小明
上方程式碼中,Ming變數可以正確在立即函式內使用。
(function(){
var Ming='小明';
console.log(Ming);
})();
console.log(Ming);
// 執行結果如下
// 小明
// Uncaught ReferenceError: Ming is not defined
可以看到小明在外層是無法正確取用的
雖然我覺得有一點雞肋...因為直接使用function時var變數也會被限制在function scope內...
雖然在ES6之後已經有Const、Let等不同於Var的宣告方式可以使用,來讓我們避免變數污染問題。但是在大型框架上仍然常可以看到匿名函式的蹤影。
參數傳遞
立即函式也可以進行參數的傳遞,範例如下:
(function (myName) {
console.log(`我的名字是${myName}`);
})('小明');
// 我的名字是小明
當然另一種IIFE的寫法也可以傳遞參數:
(function (myName) {
console.log(`我的名字是${myName}`);
}('