在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语句构成的)。