為什麽if else 語句裏不能用函數聲明定義函數,而可以用函數表達式定義函數
在《JavaScript高級程序設計》第三版第7章函數表達式部分講到,定義函數有兩種方式:一種是函數聲明,另一種就是函數表達式。函數聲明的語法是這樣的。
function functionName(arg0, arg1, arg2) {
//函數體
}
關於函數聲明,它的一個重要特征就是函數聲明提升( function declaration hoisting),意思是在執行代碼之前會先讀取函數聲明。這就意味著可以把函數聲明放在調用它的語句後面。
sayHi();
function sayHi(){
alert("Hi!");
}
這個例子不會拋出錯誤,因為在代碼執行之前會先讀取函數聲明。
第二種創建函數的方式是使用函數表達式。函數表達式有幾種不同的語法形式。下面是最常見的一種形式。
var functionName = function(arg0, arg1, arg2){
//函數體
};
這種情況下創建的函數叫做匿名函數( anonymous function),因為 function 關鍵字後面沒有標識符。(匿名函數有時候也叫拉姆達函數。)匿名函數的 name 屬性是空字符串。
函數表達式與其他表達式一樣,在使用前必須先賦值。以下代碼會導致錯誤。
sayHi(); //錯誤:函數還不存在
var sayHi = function(){
alert("Hi!");
};
理解函數提升的關鍵,就是理解函數聲明與函數表達式之間的區別。例如,執行以下代碼的結果可能會讓人意想不到。
//不要這樣做!
if(condition){
function sayHi(){
alert("Hi!");
}
} else {
function sayHi(){
alert("Yo!");
}
}
理的狀態。但問題是瀏覽器嘗試修正錯誤的做法並不一致。大多數瀏覽器會返回第二個聲明,忽略condition; Firefox 會在 condition 為 true 時返回第一個聲明。因此這種使用方式很危險,不應該
出現在你的代碼中。不過,如果是使用函數表達式,那就沒有什麽問題了。
(為什麽屬於無效的語法呢?這要從詞法作用來說,在《JavaScript語言精髓與編程實踐》第3章3.2基本語法的結構化含義 ,其中3.2.2.2語法作用域的相關性這一小節回答了以上的疑問,
以下屬於摘抄部分:
上面的代碼function的語法作用比表達式的語法作用域高,所以上面if。。。else。。。語句不能包含函數的詞法作用域,JavaScript會將其理解為“平行”的關系,即如下所示
本例中的代碼也會理解為:
if(condition){}
else {}
function sayHi(){
alert("Hi!");
}
function sayHi(){
alert("Yo!");
)
相當於第二個sayHi()函數覆蓋了第一個,所以會大多數瀏覽器會返回第二個聲明,忽略condition。
當然書中也建議如下作:
//可以這樣做
var sayHi;
if(condition){
sayHi = function(){
alert("Hi!");
};
} else {
sayHi = function(){
alert("Yo!");
};
}
這個例子不會有什麽意外,不同的函數會根據 condition 被賦值給 sayHi。
為什麽if else 語句裏不能用函數聲明定義函數,而可以用函數表達式定義函數