函數聲明時必須有函數名bash
function fn(){};
複製代碼
函數表達式中的函數能夠爲匿名函數,也能夠有函數名,可是該函數不能直接使用,只能經過表達式左邊的變量 fn 來調用閉包
var fn = function(){};
複製代碼
function a(){
console.log("函數聲明");
}
var b = function(){
console.log("函數表達式");
}
a(); //函數申明
b(); //函數表達式
複製代碼
a(); //函數聲明
b(); //報錯
function a(){
console.log("函數聲明");
}
var b = function(){
console.log("函數表達式");
}
複製代碼
爲何會有這樣的結果?
緣由: function a(){} 爲函數聲明,程序運行前就已經存在;var b = function(){} 爲函數表達式,屬於按順序執行,因此 b() 會報錯函數
在ES5中,是沒有塊級做用域的概念的;咱們主要經過匿名函數的方式來塊級做用域。
用做塊級做用域(私有做用域)的匿名函數的語法:ui
(function() { //此處是塊級(私有)做用域 })();
!function () { //此處是塊級(私有)做用域 } ();
~function () { //此處是塊級(私有)做用域 } ();
-function () { //此處是塊級(私有)做用域 } ();
+function () { //此處是塊級(私有)做用域 } ();
//這些都是當即執行的函數表達式的寫法
//定義並當即調用了一個匿名函數。將函數聲明包含在一對圓括號中,表示它其實是一個函數表達式。
複製代碼
var a = function() { console.log("IIFE 寫法的產生"); };
a(); //IIFE 寫法的產生
//咱們將一個匿名函數賦值給了一個全局變量a,而後調用了這個函數
複製代碼
(function(){
console.log("這是一個當即執行的函數");
})();
//第一個圓括號:將匿名函數轉換爲函數表達式
//第二個圓括號:當即執行匿名函數(固然,你也能夠設置一個函數名)
複製代碼
總結: 1. 建立塊級(私有)做用域,避免了向全局做用域中添加變量和函數,所以也避免了多人開發中全局變量和函數的命名衝突
2.IIFE中定義的任何變量和函數,都會在執行結束時被銷燬。這種作法能夠減小閉包占用的內存問題,由於沒有指向匿名函數的引用。只要函數執行完畢,就能夠當即銷燬其做用域鏈spa
預期: 使用 setTimeout 循環輸出 0 1 2 3 4 5code
for(var i = 0; i <= 5; i++){
setTimeout(function timer(){
console.log(i);
}, i*1000);
}
//結果:1秒內輸出6個6
複製代碼
緣由: 超時的回調函數都將在循環完成以後當即運行。
解決方法:內存
方法一:
for(var i = 0; i <= 5; i++){
(function(){
var j = i;
setTimeout(function timer(){
console.log(j);
}, j*1000)
})();
}
//結果: 0 1 2 3 4 5
複製代碼
方法二:
for(var i = 0; i <= 5; i++){
(function(j){
setTimeout(function timer(){
console.log(j);
}, j*1000)
})(i);
}
//結果: 0 1 2 3 4 5
複製代碼
IIFE 爲每次迭代建立了新的做用域,這給了超時回調函數一個機會在每次迭代時閉包一個新的做用域。作用域