1. 程式人生 > >Javascript的函數直接量定義

Javascript的函數直接量定義

命名 關於 == () .cn temp 而不是 例如 賦值

在Javascript中允許函數通過直接量來定義。一般情況下,我們定義函數時,最常見的方式是通過function語句進行定義,例如:

function sum(a,b){
return a+b;
}

這樣,sum這個函數就在它所在的作用域中可以被任意調用了。除此之外,函數的定義方式可以通過另外一種方式,就是通過直接量定義。例如上面這個例子,我們可以用另外一種方式:

var sum=function(a,b){
return a+b;
}

上述代碼就是函數通過直接量的方式進行定義。函數直接量是一個表達式,它可以定義匿名函數。函數直接量的語法和function語句十分相似,只不過, 它被用作表達式的一部分,而不是用作語句了。在函數直接量定義中,右側的function所定義的是匿名函數,並將這個匿名函數的引用傳遞給表達式左側。

關於函數直接量定義,需要說明幾點:

第一,函數直接量定義方式定義出來的函數是一個匿名函數,盡管通過表達式賦值語句將這個函數賦值給了左側的變量名,但是,左側的變量被賦值的是這個匿名函數的引用。

第二,由於函數直接量的定義方式中(代碼2),實際上function已經作為一個表達式來看待,因此,表達式左側的變量就必須在該語句執行之後才會引用 右側的匿名函數,也就是說,在該語句執行之前,作用域中僅僅是知道有個變量是sum,但是類型未知。於此相反的是,常規的函數語句(代碼1)會在 Javascript執行之前進行“預處理”,在它的作用域中,sum一開始就被認知為函數。 一個非常簡單的例子:

alert(a);//彈出undefined
alert(b);//彈出b.toString()後的結果
var a=function(){return 1;}
function b(){return 1;}
alert(a);//彈出a.toString()後的結果

上 述代碼中,第一次alert(a)時,由於“預處理”,該作用域中已經知道存在一個變量a,但是由於還沒有執行到第3行,因此,它是undefind,而 b則在一開始時,就已經知道它的類型是函數了。因此,alert(b)時,它會直接執行b.toString()方法盡管它的定義在執行語句的下面。

第三, 雖然函數直接量創建的是匿名函數,但是它的語法也規定它可以指定函數名。只不過這個函數名只在編寫調用自身的遞歸函數時非常有效。為了說明這個問題,先看下面的代碼:

var sum=function temp(n){return n==1?1:n*temp(n-1);}
alert(sum(5));//120
alert(temp(5));//出錯

上 面的代碼sum是一個計算n的階乘(n!)運算,我們可以看到,sum的定義是采用函數直接量方式定義的。但是這裏存在一個問題,就是它存在一個函數 名:temp。確切的講,temp不是函數名,因為為前面已經說了,表達式右側的function是一個匿名函數,因此,temp不可能是函數名(要不怎 麽叫匿名函數呢?)。但是,為什麽這樣的定義語法沒有錯誤呢?因為Javascript允許指定它的函數名,但是這個函數名不是真正的函數名,它是用來為 它自身遞歸調用時使用的。(函數體中實際上就是一個遞歸函數)。我大致把temp理解為匿名函數內部作用域中的函數名,它可以這樣調用它自己。因此,在執 行到alert(temp(5))時,瀏覽器報錯了,告訴我們temp是未定義的。

技術分享

但 是需要指出的是,在Javascript的早期版本中,沒有正確的實現這種命名了的函數直接量。在IE678這些版本中,Javascript的版本低於 1.5,因此,它對這種方式的處理沒有正確的實現。因此,在執行到alert(temp(5))時,它也是顯示和執行sum(5)一樣的結果。因 此,temp和sum一樣,都被賦值了。這個問題在IE9和更高的版本中,得到了統一修正

Javascript的函數直接量定義