函數聲明
function foo() {}
函數 foo 將會在整個程序執行前被 hoist (提升),因此它在定義 foo 函數的整個 scope (作用域)中都是可用的。即使在函數定義之前調用它也沒問題。
foo(); // Works because foo was created before this code runs function foo() {}
因為我打算專門寫篇介紹作用域的文章,所以這裡就不詳述了。
函數表達式
對於函數聲明,函數的名稱是必須的,而對於函數表達式而言則是可選的,因此,就出現了匿名函數表達式和命名函數表達式。如下:
函數聲明: function functionName (){ }
函數聲明: function functionName[可選](){ }
那麼我就知道,如果沒有函數名的話,一定就是函數表達式,但是對於有函數名的情況該如何判斷呢?
Javascript 規定如果整個函數體是作為表達式的一部分時,那麼它就是函數表達式,否則即是函數聲明。以下為表達式:
var fuc = foo(){}
我們再舉幾個極端的表達式例子:
!function foo(){} true && function foo(){}
以上的語句這裡只是為了區分函數表達式,一般不會這樣寫。那麼用一個對比的例子來看看效果:
foo1();//foo1 is not defined foo2();//works because foo2 was created before this code runs !function foo1() { alert('foo1 works'); }; function foo2() { alert('foo2 works'); };
匿名函數表達式
var foo = function() {};
上面的例子將一個匿名函數賦值給了變量 foo。
foo; // 'undefined' foo(); // this raises a TypeError var foo = function() {};
由於 var 是一個聲明所以這裡對變量 foo 進行 hoist (提升),因此當程序執行時,變量 foo 是可調用的。
但是由於賦值語句只有在運行時才生效,所以變量 foo 的值為 undefined。
命名函數表達式
另一個要講到的就是命名函數的賦值。
var foo = function bar() { bar(); // Works }; bar(); // ReferenceError
在這裡,命名函數 bar 賦值給了變量 foo,所以在函數聲明外是不可見的,但在 bar 函數內部仍然可以調用。這是因為 Javascript 對命名函數處理的機制,函數的名稱永遠在函數內部的作用域中有效。