立即函式 IIFE
Published in
6 min readFeb 12, 2021
IIFE 全名為Immediately Invoked Functions Expressions,
指的是可以立即執行的Functions Expressions
函式表達式。但 IIFE 最主要目的是避免污染到全域執行環境並照成污染與衝突,本篇將會介紹 IIFE 是如何執行以致於不會汙染到全域環境。
立即函式 IIFE 介紹
- 不需要呼叫此函式,也能執行 (立刻執行)
- IIFE 最主要目的是避免污染到全域執行環境並照成污染與衝突
- 限制作用域的用途,「立即函式」無法在外層呼叫
- 變數的作用域只在函式內,在外層無法取得變數
3. 「立即函式」本身是表達式,所以也能回傳一個值
以下列舉「立即函式」的特點
透過「具名函式」的方式來執行的 IIFE,且 IIFE 無法在外層被呼叫
(function IIFE() {
console.log('立即函式', IIFE);
}());
console.log(IIFE); // IIFE is not defined (無法在函式外被再次執行)
IIFE; // IIFE is not defined (「立即函式」無法在外層被呼叫)
IIFE 也是可自我執行的「匿名函式」
(function () {
console.log('立即函式'); // 立即函式
}());
小括號的位置也可移至外層
(function () {
console.log('立即函式'); // 立即函式
})();
變數只活在 IIFE 內
「立即函式」可以避免裡面的變數污染到 global scope。
變數 Ming 宣告在「立即函式」的內層,只能在「立即函式」內被取得,在外層無法取得變數。
(function() {
var Ming = '小明'; // 透過「立即函式」限制變數的作用域
console.log(Ming); // 小明
})();
console.log(Ming); // Ming is not defined (在外層無法取得變數)
限制作用域的用途
就是為了避免命名衝突,而範例中 getName 是屬於全域的函式。因此在開發中,getName 還是可能與其它變數名稱衝突,如果透過立即函式,就連同函式宣告都能限制作用域。
function getName() {
var Ming = ‘小明’;
console.log(Ming); // (限制變數的作用域)
};
getName(); // 小明
console.log(Ming); // Ming is not defined
「立即函式」也能傳遞參數
「立即函式」本身是表達式,所以也能回傳一個值
可以利用 return 並搭配一個變數來接收 IIFE
var whereMing = (function (where) {
console.log(where);
return where; // return 會把值傳出來外層,外層變數就可接收此函式
})('小明在這'); // 透過 "小括號" 把參數往前傳
console.log(whereMing);
// 小明在這 (變數 whereMing 接收此函式的 return 結果)
return用法 :
- 只要你需要將結果回傳時,就會使用到該方式。
- 這邊主要觀念與執行堆疊的記憶體釋放有關係,當函式執行完畢後就會釋放記憶體,所以若要保留結果,那麼就必須 return。
「立即函式」不符合 ASI 規則,無法自動插入分號
以下兩個「立即函式」因沒有使用分號隔開被視為同一行,
「立即函式」不符合 ASI 規則,無法自動插入分號。
(function(){
})() // 跳錯,(intermediate value)(...) is not a function(function(){
})() // 這個括號的內容不是 function
解決方法 : 在使用任何「立即函式」的前方或後方要補上分號,才能正確執行。
(function(){
})();(function(){
})()
「立即函式」傳遞變數的手法
把前一個「立即函式」的內容傳至下一個「立即函式」內
使用物件 “傳參考” 的特性傳遞
var a = {}; // 先宣告一個物件,物件有傳參考的特性
(function(b){
b.person = '小明';
console.log(b === a); // true
console.log(b.person === a.person); // true
})(a);
(function(c){
console.log(c.person); // 小明
console.log(c === a); // true
console.log(c.person === a.person); // true
})(a)
- function(b) 和 function(c) 裡面的 b 和 c 參數,都是傳進來 a 的值。
如果將 a 與 b 和 c 比較會發現都為 true。 a 與參數 b、c 的值是一樣的。 - 有一個 a 的物件帶到 b,又因為物件是傳參考,所以 a 和 b 的參考路徑都是相同,所以 b.person=小明; 實際上因參考路徑相同所以 a、b 底下都有一個屬性 person 跟值小明,第二個立即函式也接收了 a 的參考路徑故 console.log(c.person); //小明 。 a、b、c的參考路徑都是相同。
將參數掛載到 window 全域物件的方式傳遞
將 window 傳入,可以確保框架正確的掛載到全域變數 window 上
(function(global) {
global.person = '小明';
})(window) // window 是全域物件,把 window 全域物件傳到前面這個「立即函式」
;(function(c) {
console.log(person); // 小明
})()
- 將傳進第一個立即函式的參數改為全域物件 window。第二個立即函式印出全域物件的屬性 person。
- window 是一個物件,而透過 global 傳入後也是一個物件傳參考特性,因此 global.person 其實就是 window.person。
- window 是全域物件,把 window 全域物件傳到前面的立即函式,在全域物件掛上屬性 person,並把值傳到另一個立即函式。
var greeting = 'Hola';
(function(global, name){
var greeting = 'Hello';
global.greeting = 'Hello' // 讓 Hola 變成 Hello
console.log(greeting+' '+name) // Hello Iris
})(window, 'Iris') // 取用全域中的變數,並代入 IIFE 中來更改全域變數
console.log(greeting) // Hello