IIFE
IIFE: Immediately Invoked Function Expression,翻譯過來就是立即呼叫的函式表示式。也就是說,在函式宣告的同時立即呼叫這個函式。
普通的函式宣告和函式呼叫
function bar() {
var a = 10;
console.log(a);
}
bar(); // 函式呼叫
複製程式碼
IIFE函式宣告和呼叫
(function foo(){
var a = 10;
console.log(a);
})();
複製程式碼
首先注意一點的就是IIFE函式是由一對()將函式宣告包裹起來的表示式。使得JS編譯器不再認為這是一個函式宣告,而是一個IIFE,即立刻執行函式表示式。 但是兩者達到的目的都是一樣的,都是宣告瞭一個函式並且隨後呼叫這個函式。
為什麼要使用IIFE
如果只是為了立即執行一個函式,顯然IIFE所帶來的好處有限。實際上,IIFE的出現是為了彌補JS在scope方面的缺陷:JS只有全域性作用域(global scope)、函式作用域(function scope),從ES6開始才有塊級作用域(block scope)。對比現在流行的其他物件導向的語言可以看出,JS在訪問控制這方面是多麼的脆弱!那麼如何實現作用域的隔離呢?在JS中,只有function才能實現作用域隔離,因此如果要將一段程式碼中的變數、函式等的定義隔離出來,只能將這段程式碼封裝到一個函式中。
為呼叫一次的函式達到作用域隔離、命名衝突、減少記憶體佔用問題。
塊級作用域
在ES5中是沒有塊級作用域的概念。只有全域性作用域和函式作用域
for (var i = 0; i< 10; i++) {
console.log(i);
}
console.log(i); // 10
複製程式碼
這個地方可以看出for迴圈中的變數i是一個全域性變數,在for迴圈執行完畢後這個i還是可以訪問到的。i並沒有被銷燬
塊級作用域也可以稱為私有作用域。也就是說只在for迴圈的語句塊中有定義,一旦迴圈結束,變數i就會被銷燬,而在ES5中我們主要使用匿名函式【IIFE】的方式來達到塊級作用域的效果。
IIFE實現作用域隔離
// 函式宣告語句寫法
function test() {};
test();
// 函式表示式寫法
var test = function(){};
test();
複製程式碼
[注意]javascript引擎規定,如果function關鍵字出現在行首,一律解釋成函式宣告語句;而函式宣告後面是不能跟圓括號的(匿名函式是函式宣告的一種)。然而,函式表示式的後面可以跟圓括號。所以可以將函式宣告轉換成函式表示式。 在立即執行函式中,定義的變數會在立即
所以,解決方法就是不要讓function出現在行首,讓引擎將其理解成一個表示式 最常用的幾種辦法
(function(){
console.log('123');
}());
(function(){
console.log('123');
})();
(function foo(){
console.log('123');
})();
複製程式碼
分號
對於立即執行函式末尾的;分號,最好加上,因為如果不加,遇到兩個都是用括號()包裹執行的IIFE時,就會遇到問題。
(function(){
console.log('a');
})()
(function(){
console.log('b');
})()
複製程式碼
這一段程式碼只有a可以顯示出來,b會報錯
TypeError: (intermediate value)(...) is not a function
不加分號,上面的內容會被JS理解為:
(function(){
console.log('a');
})()(function(){
console.log('b');
})()
複製程式碼
也就是說,a匿名函式執行後,沒有;的隔斷,後面的b立即執行函式與a合成了一個函式。執行到輸出完a時,沒有reutrn,後面的()相當於對undefined進行了執行,所以報錯。
我們可以這樣修改
(function(){
console.log('a');
})()
(function(){
console.log('b');
}())
複製程式碼
這樣修改後,a,b都會顯示出來,但是同樣會報錯, 還有其他的修改方式,但是我建議加上;分號避免報錯。
IIFE的優點
- 建立塊級(私有)作用域,避免了向全域性作用域中新增變數和函式,因此也避免了多人開發中全域性變數和函式的命名衝突。
- IIFE中定義的任何變數和函式,都會在執行結束時被銷燬,這種做法可以減少閉包占用的記憶體問題,因為沒有指向匿名函式的引用。只要函式執行完畢,就可以立即銷燬其作用域鏈了。
歡迎關注微信公眾號