一. 函數(shù)聲明
// 函數(shù)聲明
function funDeclaration(type){ return type==="Declaration"; }
二. 函數(shù)表達(dá)式
// 函數(shù)表達(dá)式
var funExpression = function(type){ return type==="Expression"; }
用函數(shù)聲明創(chuàng)建的函數(shù)funDeclaration可以在funDeclaration定義之前就進(jìn)行調(diào)用;而用函數(shù)表達(dá)式創(chuàng)建的funExpression函數(shù)不能在funExpression被賦值之前進(jìn)行調(diào)用。
為什么會這樣呢?!這就要理解Javascript Function兩種類型的區(qū)別:用函數(shù)聲明創(chuàng)建的函數(shù)可以在函數(shù)解析后調(diào)用(解析時進(jìn)行等邏輯處理);而用函數(shù)表達(dá)式創(chuàng)建的函數(shù)是在運(yùn)行時進(jìn)行賦值,且要等到表達(dá)式賦值完成后才能調(diào)用。
這個區(qū)別看似微小,但在某些情況下確實(shí)是一個難以發(fā)現(xiàn)的陷阱。出現(xiàn)這個陷阱的本質(zhì)原因體現(xiàn)在這兩種類型在Javascript function hoisting(函數(shù)提升)和運(yùn)行時機(jī)(解析時/運(yùn)行時)上的差異
三. 提升
誰會被提升
變量聲明:使用var ,let ,const關(guān)鍵字
函數(shù)聲明:使用function(){......}語法
類聲明:使用class關(guān)鍵字
- 函數(shù)聲明在函數(shù)作用域內(nèi)創(chuàng)建并初始化一個變量。默認(rèn)情況下,聲明但是未初始化的變量的值是undefined。
- javascript并沒有嚴(yán)格遵循這個順序,因此提供了更多的靈活性。比如:函數(shù)的使用可以在聲明之前。(目前就這個)
var foo;
function foo(){
console.log(1);
}
foo = function(){
console.log(2);
}```
會輸出1二不是2!這個代碼片段會被引擎理解為如下形式:
function foo(){
console.log(1);
}
foo();//1
foo = function(){
console.log(1);
}
foo();//1
注意:var foo盡管出現(xiàn)在 function foo()...的聲明之前,但它是重復(fù)的聲明(因此被忽略了),因?yàn)楹瘮?shù)聲明會被提升到普通變量之前。
盡管**重復(fù)的var** 聲明會被忽略掉,但出現(xiàn)在后面的函數(shù)聲明還是可以**覆蓋**前面的。
##四. 總結(jié)
無論作用域中的聲明出現(xiàn)在什么地方,都將在代碼本身被執(zhí)行前首先進(jìn)行處理??梢詫⑦@個過程形象地想象成所有的聲明(變量和函數(shù))都會被“移動”到各自作用域的最頂端,這個過程被稱為提升。
聲明本身會被提升,而包括函數(shù)表達(dá)式的賦值在內(nèi)的賦值操作并不會提升。要注意避免重復(fù)聲明,特別是當(dāng)普通的var 聲明和函數(shù)聲明混合在一起的時候,否則會引起很多危險(xiǎn)的問題!
**參考至《你不知道的Javascript 上卷》**