IIFE: Immediately Invoked Function Expression,翻譯過來就是當即調用的函數表達式。也就是說,在函數聲明的同時當即調用這個函數。javascript
普通的函數聲明和函數調用java
function bar() { var a = 10; console.log(a); } bar(); // 函數調用 複製代碼
IIFE函數聲明和調用bash
(function foo(){ var a = 10; console.log(a); })(); 複製代碼
首先注意一點的就是IIFE函數是由一對()將函數聲明包裹起來的表達式。使得JS編譯器再也不認爲這是一個函數聲明,而是一個IIFE,即馬上執行函數表達式。 可是二者達到的目的都是同樣的,都是聲明瞭一個函數而且隨後調用這個函數。微信
若是隻是爲了當即執行一個函數,顯然IIFE所帶來的好處有限。實際上,IIFE的出現是爲了彌補JS在scope方面的缺陷:JS只有全局做用域(global scope)、函數做用域(function scope),從ES6開始纔有塊級做用域(block scope)。對比如今流行的其餘面向對象的語言能夠看出,JS在訪問控制這方面是多麼的脆弱!那麼如何實現做用域的隔離呢?在JS中,只有function才能實現做用域隔離,所以若是要將一段代碼中的變量、函數等的定義隔離出來,只能將這段代碼封裝到一個函數中。markdown
爲調用一次的函數達到做用域隔離、命名衝突、減小內存佔用問題。閉包
在ES5中是沒有塊級做用域的概念。只有全局做用域和函數做用域函數
for (var i = 0; i< 10; i++) { console.log(i); } console.log(i); // 10 複製代碼
這個地方能夠看出for循環中的變量i是一個全局變量,在for循環執行完畢後這個i仍是能夠訪問到的。i並無被銷燬spa
塊級做用域也能夠稱爲私有做用域。也就是說只在for循環的語句塊中有定義,一旦循環結束,變量i就會被銷燬,而在ES5中咱們主要使用匿名函數【IIFE】的方式來達到塊級做用域的效果。翻譯
// 函數聲明語句寫法 function test() {}; test(); // 函數表達式寫法 var test = function(){}; test(); 複製代碼
[注意]javascript引擎規定,若是function關鍵字出如今行首,一概解釋成函數聲明語句;而函數聲明後面是不能跟圓括號的(匿名函數是函數聲明的一種)。然而,函數表達式的後面能夠跟圓括號。因此能夠將函數聲明轉換成函數表達式。 在當即執行函數中,定義的變量會在當即code
因此,解決方法就是不要讓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都會顯示出來,可是一樣會報錯, 還有其餘的修改方式,可是我建議加上;分號避免報錯。
歡迎關注微信公衆號