函數(shù)聲明
函數(shù)聲明時(shí)必須有函數(shù)名
function fn(){};
函數(shù)表達(dá)式
函數(shù)表達(dá)式中的函數(shù)可以為匿名函數(shù)糠馆,也可以有函數(shù)名疾呻,但是該函數(shù)不能直接使用落塑,只能通過(guò)表達(dá)式左邊的變量 fn 來(lái)調(diào)用
var fn = function(){};
看看兩者區(qū)別
function a(){
console.log("函數(shù)聲明");
}
var b = function(){
console.log("函數(shù)表達(dá)式");
}
a(); //函數(shù)申明
b(); //函數(shù)表達(dá)式
a(); //函數(shù)聲明
b(); //報(bào)錯(cuò)
function a(){
console.log("函數(shù)聲明");
}
var b = function(){
console.log("函數(shù)表達(dá)式");
}
為什么會(huì)有這樣的結(jié)果?
原因: function a(){} 為函數(shù)聲明罐韩,程序運(yùn)行前就已經(jīng)存在憾赁;var b = function(){} 為函數(shù)表達(dá)式,屬于按順序執(zhí)行散吵,所以 b() 會(huì)報(bào)錯(cuò)
進(jìn)入IIFE (立即執(zhí)行的函數(shù)表達(dá)式)
在ES5中龙考,是沒(méi)有塊級(jí)作用域的概念的;我們主要通過(guò)匿名函數(shù)的方式來(lái)塊級(jí)作用域矾睦。
用作塊級(jí)作用域(私有作用域)的匿名函數(shù)的語(yǔ)法:
(function() { //此處是塊級(jí)(私有)作用域 })();
!function () { //此處是塊級(jí)(私有)作用域 } ();
~function () { //此處是塊級(jí)(私有)作用域 } ();
-function () { //此處是塊級(jí)(私有)作用域 } ();
+function () { //此處是塊級(jí)(私有)作用域 } ();
//這些都是立即執(zhí)行的函數(shù)表達(dá)式的寫(xiě)法
//定義并立即調(diào)用了一個(gè)匿名函數(shù)晦款。將函數(shù)聲明包含在一對(duì)圓括號(hào)中,表示它實(shí)際上是一個(gè)函數(shù)表達(dá)式枚冗。
IIFE 寫(xiě)法的產(chǎn)生:
var a = function() { console.log("IIFE 寫(xiě)法的產(chǎn)生"); };
a(); //IIFE 寫(xiě)法的產(chǎn)生
//我們將一個(gè)匿名函數(shù)賦值給了一個(gè)全局變量a缓溅,然后調(diào)用了這個(gè)函數(shù)
衍生出 IIFE 寫(xiě)法
(function(){
console.log("這是一個(gè)立即執(zhí)行的函數(shù)");
})();
//第一個(gè)圓括號(hào):將匿名函數(shù)轉(zhuǎn)換為函數(shù)表達(dá)式
//第二個(gè)圓括號(hào):立即執(zhí)行匿名函數(shù)(當(dāng)然,你也可以設(shè)置一個(gè)函數(shù)名)
總結(jié): 1. 創(chuàng)建塊級(jí)(私有)作用域赁温,避免了向全局作用域中添加變量和函數(shù)坛怪,因此也避免了多人開(kāi)發(fā)中全局變量和函數(shù)的命名沖突
2.IIFE中定義的任何變量和函數(shù),都會(huì)在執(zhí)行結(jié)束時(shí)被銷(xiāo)毀股囊。這種做法可以減少閉包占用的內(nèi)存問(wèn)題袜匿,因?yàn)闆](méi)有指向匿名函數(shù)的引用。只要函數(shù)執(zhí)行完畢稚疹,就可以立即銷(xiāo)毀其作用域鏈
常用實(shí)例
預(yù)期: 使用 setTimeout 循環(huán)輸出 0 1 2 3 4 5
for(var i = 0; i <= 5; i++){
setTimeout(function timer(){
console.log(i);
}, i*1000);
}
//結(jié)果:1秒內(nèi)輸出6個(gè)6
原因: 超時(shí)的回調(diào)函數(shù)都將在循環(huán)完成之后立即運(yùn)行居灯。
解決方法:
方法一:
for(var i = 0; i <= 5; i++){
(function(){
var j = i;
setTimeout(function timer(){
console.log(j);
}, j*1000)
})();
}
//結(jié)果: 0 1 2 3 4 5
方法二:
for(var i = 0; i <= 5; i++){
(function(j){
setTimeout(function timer(){
console.log(j);
}, j*1000)
})(i);
}
//結(jié)果: 0 1 2 3 4 5
IIFE 為每次迭代創(chuàng)建了新的作用域,這給了超時(shí)回調(diào)函數(shù)一個(gè)機(jī)會(huì)在每次迭代時(shí)閉包一個(gè)新的作用域内狗。