先看以下幾段燒腦的代碼:
f();//=>? var f = function () { console.log("var"); } function f() { console.log("function"); }
控制台打印結果"function"。
另一段代碼
var f = function () { console.log("var"); } function f() { console.log("function"); } f();//=>?
控制台打印結果"var"。
關於函數聲明和函數表達式更具體的定義在javascript函數中有相關詳細的介紹,這里就不再敘述。上述代碼主要用於引出函數聲明和函數表達式的區別。
函數聲明和函數表達式的區別本質其實是函數聲明提升和變量聲明提升的區別。
一般變量的聲明為以下形式:
var a=10;
js在預編譯階段,是這么處理的:
//預編譯階段 var a; //執行階段 a=10;
預編譯階段,js將其分解為變量聲明與變量賦值。
一般函數聲明:
function fDeclaration(){ console.log("declaration"); }
預編譯階段,js將其分解為類似以下的變量聲明與變量賦值:
//預編譯 var fDeclaration; fDeclaration = function () { console.log("declaration"); }
在標識符相同的情況下,js如何處理變量與函數呢?
var f = function () { console.log("var"); } function f() { console.log("function"); } f();//=> 在控制台會打印什么結果呢?
函數聲明提前優先於變量聲明提前。因此上面代碼JS預編譯會做類似如下處理:
/* 預編譯階段 *函數聲明提前優先級別更高,先進行預編譯,並對f進行了賦值。 *在預編譯階段后於函數聲明,f經歷兩次賦值,后來的賦值替代了原先的賦值,表現為f執行函數表達式。 */ //函數聲明預編譯階段 var f; f = function () { console.log("function"); } //函數表達式提前預編譯,由於它是變量聲明,變量聲明提前是只有聲明提前,而沒有賦值提前。 //重復的聲明,js會忽略 var f; /*執行階段*/ //變量f再次賦值 f = function () { console.log("var"); } f();//=>"var"