在ECMAScript中,建立函數的最經常使用的兩個方法是函數表達式和函數聲明,由於ECMA規範只明確了一點:函數聲明必須帶有標示符(Identifier)(就是你們常說的函數名稱),而函數表達式則能夠省略這個標示符:json
函數聲明:函數
function 函數名稱 (參數:可選){ 函數體 }spa
函數表達式:code
function 函數名稱(可選)(參數:可選){ 函數體 }blog
因此,能夠看出,若是不聲明函數名稱,它確定是表達式,可若是聲明瞭函數名稱的話,如何判斷是函數聲明仍是函數表達式呢?ECMAScript是經過上下文來區分的,若是function foo(){}是做爲賦值表達式的一部分的話,那它就是一個函數表達式,若是function foo(){}被包含在一個函數體內,或者位於程序的最頂部的話,那它就是一個函數聲明。ip
function foo(){} // 聲明,由於它是程序的一部分 var bar = function foo(){}; // 表達式,由於它是賦值表達式的一部分 new function bar(){}; // 表達式,由於它是new表達式
(function(){ function bar(){} // 聲明,由於它是函數體的一部分 })();
還有一種函數表達式不太常見,就是被括號括住的(function foo(){}),他是表達式的緣由是由於括號 ()是一個分組操做符,它的內部只能包含表達式作用域
你能夠會想到,在使用eval對JSON進行執行的時候,JSON字符串一般被包含在一個圓括號裏:eval('(' + json + ')'),這樣作的緣由就是由於分組操做符,也就是這對括號,會讓解析器強制將JSON的花括號解析成表達式而不是代碼塊。字符串
(function foo(){}); // 函數表達式:包含在分組操做符內
表達式和聲明存在着十分微妙的差異,首先,函數聲明會在任何表達式被解析和求值以前先被解析和求值,即便你的聲明在代碼的最後一行,它也會在同做用域內第一個表達式以前被解析/求值,參考以下例子,函數fn是在alert以後聲明的,可是在alert執行的時候,fn已經有定義了:io
alert(fn());//Hello world!
function fn() { return 'Hello world!'; }
函數聲明的實際規則以下:function
函數聲明只能出如今程序或函數體內。從句法上講,它們 不能出如今Block(塊)({ ... })中,例如不能出如今 if、while 或 for 語句中。由於 Block(塊) 中只能包含Statement語句, 而不能包含函數聲明這樣的源元素。另外一方面,仔細看一看規則也會發現,惟一可能讓表達式出如今Block(塊)中情形,就是讓它做爲表達式語句的一部分。可是,規範明確規定了表達式語句不能以關鍵字function開頭。而這實際上就是說,函數表達式一樣也不能出如今Statement語句或Block(塊)中(由於Block(塊)就是由Statement語句構成的)。