1. 程式人生 > >為什麽if else 語句裏不能用函數聲明定義函數,而可以用函數表達式定義函數

為什麽if else 語句裏不能用函數聲明定義函數,而可以用函數表達式定義函數

java 關鍵字 {} 作用 關系 另一個 else 語法 出錯

在《JavaScript高級程序設計》第三版第7章函數表達式部分講到,定義函數有兩種方式:一種是函數聲明,另一種就是函數表達式。函數聲明的語法是這樣的。
function functionName(arg0, arg1, arg2) {
//函數體
}

於函數聲明,它的一個重要特征就是函數聲明提升function declaration hoisting),意思是在執行代碼之前會先讀取函數聲明。這就意味著可以把函數聲明放在調用它的語句後面。
sayHi();
function sayHi(){
alert("Hi!");
}
這個例子不會拋出錯誤,因為在代碼執行之前會先讀取函數聲明。


第二種創建函數的方式是使用函數表達式。函數表達式有幾種不同的語法形式。下面是最常見的一種形式。
var functionName = function(arg0, arg1, arg2){
//函數體
};

這種形式看起來好像是常規的變量賦值語句,即創建一個函數並將它賦值給變量 functionName
這種情況下創建的函數叫做匿名函數anonymous function),因為 function 關鍵字後面沒有標識符。(匿名函數有時候也叫拉姆達函數。)匿名函數的 name 屬性是空字符串。
函數表達式與其他表達式一樣,在使用前必須先賦值。以下代碼會導致錯誤。
sayHi(); //錯誤:函數還不存在
var sayHi = function(){
alert("Hi!");
};
理解函數提升的關鍵,就是理解函數聲明與函數表達式之間的區別。例如,執行以下代碼的結果可能會讓人意想不到。
//不要這樣做!
if(condition){
function sayHi(){
alert("Hi!");
}
} else {
function sayHi(){
alert("Yo!");
}
}
表面上看,以上代碼表示在 condition true 時,使用一個 sayHi()的定義;否則,就使用另一個定義。實際上,這在 ECMAScript 中屬於無效語法, JavaScript 引擎會嘗試修正錯誤,將其轉換為合
理的狀態。但問題是瀏覽器嘗試修正錯誤的做法並不一致。大多數瀏覽器會返回第二個聲明,忽略conditionFirefox 會在 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 語句裏不能用函數聲明定義函數,而可以用函數表達式定義函數