當即執行函數表達式,其實也能夠叫初始化函數表達式,英文名:IIFE,immediately-inovked-function expression。當即執行函數表達式就是在定義的時候就當即執行。html
1)寫法一express
1 (function (a) { 2 console.log('The result is ' + a); 3 })(5); 4 // The result is 5
2)寫法二segmentfault
1 (function (a) { 2 console.log('The result is ' + a); 3 }(5)); 4 // The result is 5
1)做用域隔離,避免污染全局的命名空間數組
經過定義一個匿名函數,建立了一個新的函數做用域,至關於建立了一個「私有」的命名空間,該命名空間的變量和方法,不會破壞污染全局的命名空間。若是想傳給外部變量或者方法,經過給window上添加對應屬性便可。瀏覽器
例如:Jquery插件就是將window傳入,而後給window上添加了$屬性。閉包
2)執行完當即銷燬ide
執行完後,內部的局部變量和整個函數會被銷燬釋放掉。函數
1 (function add(a, b) { 2 console.log('The result is ' + (a + b)); 3 return a + b; 4 }(5, 3)); 5 6 add(4, 6); 7 8 // The result is 8 9 // Uncaught ReferenceError: add is not defined
3)當即執行函數表達式不須要帶函數名this
若是帶了函數名,則被自動忽略。spa
下邊會針對一些當即執行函數表達式的錯誤寫法,深刻說明其緣由。
要很好的理解下邊錯誤寫法的緣由,首先要了解:JavaScript中函數的定義方法;JavaScript中表達式。
1)錯誤寫法一
下邊的錯誤寫法的緣由:瀏覽器解析器遇到function開頭的語句,認爲這是一個函數定義,但發現該函數沒有函數名,致使報錯。
1 function () { 2 console.log('The result is 1'); 3 }(); 4 5 // Uncaught SyntaxError: Unexpected token (
說明:爲何給上邊示例代碼添加一個圓括號,就能夠執行而且不報錯了?
這是由於添加圓括號後,就變成表達式。
咱們都知道定義函數有兩種方式:
1 // 函數聲明:使用function聲明函數,並指定函數名 2 function add() { 3 console.log('The result is 1'); 4 } 5 6 // 函數表達式:使用function聲明函數,但未指定函數名,將匿名函數賦予一個變量 7 var add = function() { 8 console.log('The result is 1'); 9 };
所以當即執行函數表達式,就相似於給函數表達式方式定義的函數,只是在函數定義完添加了圓括號讓該函數當即執行了。
根本的緣由仍是將一個函數定義,變成了一個表達式。這也是爲何叫當即執行函數表達式的緣由。
讓一個匿名函數變成一個表達式的方法不少:
1 !function(){}(); 2 +function(){}(); 3 -function(){}(); 4 ~function(){}(); 5 new function(){ /* code */ } 6 new function(){ /* code */ }() // 只有傳遞參數時,才須要最後那個圓括號。 7 ……
2)錯誤寫法二
1 function add() { 2 console.log('The result is ' + a); 3 }(); 4 5 // Uncaught SyntaxError: Unexpected token )
上邊代碼會被瀏覽器解析爲以下樣子:
1 function add() { 2 console.log('The result is ' + a); 3 }; 4 ();
第一個分號前是一個完整的函數定義,沒有問題;而第二個分號前的(),出現了語法報錯。
注意:當咱們給後邊的那個圓括號中添加一個表達式後,就不會報錯了。但注意add函數依然不會執行。
1 function add() { 2 console.log('The result is 1'); 3 }(2); 4 5 6 // 上邊等價於下邊代碼:一部分是函數聲明,一部分是執行表達式。所以函數不會執行。 7 function add() { 8 console.log('The result is 1'); 9 }; 10 (2);
3)錯誤寫法三
當有多個當即執行函數表達式時,必定要帶分號:
1 (function () { 2 console.log('this is IIFE 1'); 3 }()) 4 (function () { 5 console.log('this is IIFE 1'); 6 }()) 7 8 // VM80:4 Uncaught TypeError: (intermediate value)(...) is not a function
說明:不帶分號會致使JavaScript執行器認爲後邊括號內容是前邊括號內容的參數,而前邊括號最終執行結果並非一個函數。而下邊代碼就不會報錯:
1 (function () { 2 console.log('this is IIFE 1'); 3 return function(a) { 4 console.log('this is IIFE 1 return'); 5 } 6 }()) 7 (function () { 8 console.log('this is IIFE 2'); 9 }()) 10 11 // this is IIFE 1 12 // this is IIFE 2 13 // this is IIFE 1 return
1 // 這個代碼是錯誤的,由於變量i歷來就沒背locked住 2 // 相反,當循環執行之後,咱們在點擊的時候i纔得到數值 3 // 由於這個時候i操真正得到值 4 // 因此說不管點擊那個鏈接,最終顯示的都是I am link #10(若是有10個a元素的話) 5 6 var elems = document.getElementsByTagName('a'); 7 8 for (var i = 0; i < elems.length; i++) { 9 10 elems[i].addEventListener('click', function (e) { 11 e.preventDefault(); 12 alert('I am link #' + i); 13 }, 'false'); 14 15 } 16 17 // 這個是能夠用的,由於他在自執行函數表達式閉包內部 18 // i的值做爲locked的索引存在,在循環執行結束之後,儘管最後i的值變成了a元素總數(例如10) 19 // 但閉包內部的lockedInIndex值是沒有改變,由於他已經執行完畢了 20 // 因此當點擊鏈接的時候,結果是正確的 21 22 var elems = document.getElementsByTagName('a'); 23 24 for (var i = 0; i < elems.length; i++) { 25 26 (function (lockedInIndex) { 27 28 elems[i].addEventListener('click', function (e) { 29 e.preventDefault(); 30 alert('I am link #' + lockedInIndex); 31 }, 'false'); 32 33 })(i); 34 35 } 36 37 // 你也能夠像下面這樣應用,在處理函數那裏使用自執行函數表達式 38 // 而不是在addEventListener外部 39 // 可是相對來講,上面的代碼更具可讀性 40 41 var elems = document.getElementsByTagName('a'); 42 43 for (var i = 0; i < elems.length; i++) { 44 45 elems[i].addEventListener('click', (function (lockedInIndex) { 46 return function (e) { 47 e.preventDefault(); 48 alert('I am link #' + lockedInIndex); 49 }; 50 })(i), 'false'); 51 52 }
博客園:https://www.cnblogs.com/tomxu/archive/2011/12/31/2289423.html
SF:http://www.javashuo.com/article/p-pldiqnob-cr.html
百度:https://baijiahao.baidu.com/s?id=1627496475450434415&wfr=spider&for=pc