函數表達式
函數表達式的特征
使用函數實作遞歸
使用閉包定義私有變量
數表達式是 JavaScript 中的一個既強大又容易令人困惑的特性。第 5 章曾介紹過,定義函數的方式有兩種:
一種是函數聲明,
另一種就是函數表達式。
函數聲明的文法是這樣的:
function functionName(arg0, arg1, arg2) {
//函數體
}
首先是 function 關鍵字,然後是函數的名字,這就是指定函數名的方式。Firefox、Safari、Chrome和 Opera
都給函數定義了一個非标準的 name 屬性,通過這個屬性可以通路到給函數指定的名字。
這個屬性的值永遠等于跟在 function 關鍵字後面的辨別符。
//隻在 Firefox、Safari、Chrome 和 Opera 有效
alert(functionName.name); //"functionName"
關于函數聲明,它的一個重要特征就是函數聲明提升(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 引擎會嘗試修正錯誤,将其轉換為合理的狀态。但問題是浏覽器嘗試修正錯誤的做法并不一緻。大多數浏覽器會傳回第二個聲明,忽略condition;
Firefox 會在 condition 為 true 時傳回第一個聲明。是以這種使用方式很危險,不應該出現在你的代碼中。不過,如果是使用函數表達式,那就沒有什麼問題了。
//可以這樣做
var sayHi;
if(condition){
sayHi = function(){
alert("Hi!");
};
} else {
sayHi = function(){
alert("Yo!");
};
}
這個例子不會有什麼a意外,不同的函數會根據 condition 被指派給 sayHi。
能夠建立函數再指派給變量,也就能夠把函數作為其他函數的值傳回。還記得第 5 章中的那個
createComparisonFunction()函數嗎:
function createComparisonFunction(propertyName) {
return function(object1, object2){
var value1 = object1[propertyName];
var value2 = object2[propertyName];
圖靈社群會員 StinkBC([email protected]) 專享 尊重版權