定義函數(shù)的方式有兩種:
- 函數(shù)聲明
重要特征就是函數(shù)聲明提升,意思是在執(zhí)行代碼之前會先讀取函數(shù)聲明筋栋。這就意味著可以把函數(shù)聲明放在調(diào)用它的語句后面炊汤。 - 函數(shù)表達(dá)式
函數(shù)表達(dá)式有幾種不同的語法形式。下面是最常見的一種形式弊攘。
<pre>
var functionName = function(arg0, arg1, arg2){
//函數(shù)體
};
</pre>
函數(shù)表達(dá)式與其他表達(dá)式一樣抢腐,在使用前必須先賦值。
<pre>
sayHi(); //錯誤:函數(shù)還不存在
var sayHi = function(){
alert("Hi!");
};
</pre>
理解函數(shù)提升的關(guān)鍵襟交,就是理解函數(shù)聲明和函數(shù)表達(dá)式之間的區(qū)別迈倍。
<pre>
//不要這樣做!
if(condition){
function sayHi(){
alert("Hi!");
}
}
else {
function sayHi(){
alert("Yo!");
}
}
</pre>
不過捣域,如果是使用函數(shù)表達(dá)式啼染,那就沒有什么問題了宴合。
<pre>
//可以這樣做
var sayHi;
if(condition){
sayHi = function(){
alert("Hi!");
};
}
else {
sayHi = function(){
alert("Yo!");
};
}
</pre>
7.1 遞歸
arguments.callee 是一個指向正在執(zhí)行的函數(shù)的指針,因此可以用它來實現(xiàn)對函數(shù)的遞歸調(diào)用
<pre>
function factorial(num){
if(num<=1){
return 1;
}
else{
return numarguments.callee(num-1);*
}
}
</pre>
但是在嚴(yán)格模式下迹鹅,不能通過腳本訪問arguments.callee檐蚜,訪問這個屬性會導(dǎo)致錯誤宝踪。不過,可以使用命名函數(shù)表達(dá)式來達(dá)成相同的結(jié)果。
<pre>
var factorial = (function f(num){
if(num <= 1){
return 1;
}
else{
return num * f(num - 1);
}
})
</pre>
7.2 閉包
閉包是指有權(quán)訪問另一個函數(shù)作用域中的變量的函數(shù)篡腌。創(chuàng)建閉包的常見方式疟呐,就是在一個函數(shù)內(nèi)部常見另一個函數(shù)译柏。
7.2.1 閉包與變量
- 作用域鏈的這種配置機(jī)制引出了一個值得注意的副作用挑豌,即閉包只能取得包含函數(shù)中任何變量的最后一個值。
- 閉包所保存的是整個變量對象义钉,而不是某個特殊的變量昧绣。
<pre>
function createFunctions(){
var result = new Array();
for (var i=0; i < 10; i++){
result[i] = function(){
return i;
};
}
return result;
}
</pre>
這個函數(shù)會返回一個函數(shù)數(shù)組。表面上看捶闸,似乎每個函數(shù)都應(yīng)該返自己的索引值滞乙,即位置 0 的函數(shù)返回 0,位置 1 的函數(shù)返回 1鉴嗤,以此類推斩启。但實際上,每個函數(shù)都返回 10醉锅。因為每個函數(shù)的作用域鏈中都保存著 createFunctions() 函數(shù)的活動對象兔簇,所以它們引用的都是同一個變量 i 。當(dāng)createFunctions() 函數(shù)返回后硬耍,變量 i 的值是 10垄琐,此時每個函數(shù)都引用著保存變量 i 的同一個變量對象,所以在每個函數(shù)內(nèi)部 i 的值都是 10经柴。
但是狸窘,我們可以通過創(chuàng)建另一個匿名函數(shù)強(qiáng)制讓閉包的行為符合預(yù)期。
<pre>
function createFunctions(){
var result = new Array();
for (var i=0; i < 10; i++){
result[i] = function(num){
return function(){
return num;
};
}(i);
}
return result;
}
</pre>
在重寫了前面的 createFunctions() 函數(shù)后坯认,每個函數(shù)就會返回各自不同的索引值了翻擒。在這個版本中,我們沒有直接把閉包賦值給數(shù)組牛哺,而是定義了一個匿名函數(shù)陋气,并將立即執(zhí)行該匿名函數(shù)的結(jié)果賦給數(shù)組。這里的匿名函數(shù)有一個參數(shù) num 引润,也就是最終的函數(shù)要返回的值巩趁。在調(diào)用每個匿名函數(shù)時,我們傳入了變量 i 淳附。由于函數(shù)參數(shù)是按值傳遞的议慰,所以就會將變量 i 的當(dāng)前值復(fù)制給參數(shù) num 蠢古。而在這個匿名函數(shù)內(nèi)部,又創(chuàng)建并返回了一個訪問 num 的閉包别凹。這樣一來草讶, result 數(shù)組中的每個函數(shù)都有自己num 變量的一個副本,因此就可以返回各自不同的數(shù)值了番川。