记得在面试腾讯实习生的时候,面试官问了我这样一道问题。
代码如下:
//下述两种声明方式有什么不同
function foo(){};
var bar = function foo(){};
当初只知道两种声明方式一个是函数声明一个是函数表达式,具体有什么不同没能说得很好。最近正好看到这方面的书籍,就想好好总结一番。
在ECMAScript中,有两个最常用的创建函数对象的方法,即使用函数表达式或者使用函数声明。对此,ECMAScript规范明确了一点,即是,即函数声明 必须始终带有一个标识符(Identifier),也就是我们所说的函数名,而函数表达式则可以省略。
函数声明:
代码如下:
function Identifier ( FormalParameterList opt){ FunctionBody }
函数声明解析过程如下:
1. 创建一个new Function对象,FormalParameterList指定参数,FunctionBody指定函数体。将当前正在运行环境中作用域链作为它的作用域。
2. 为当前变量对象创建一个名为Identifier的属性,值为Result(1)。
函数表达式:
(函数表达式分为匿名和具名函数表达式)
代码如下:
function Identifier opt( FormalParameterList opt){ FunctionBody } //这里是具名函数表达式
具名函数表达式的解析过程如下:
1. 创建一个new Object对象
2. 将Result(1)添加到作用域链的顶端
3. 创建一个new Function对象,FormalParameterList指定参数,FunctionBody指定函数体。将当前正在运行的执行环境中作用域链作为它的作用域。
4. 为Result(1)创建一个名为Identifier 的属性,其值为为Result(3),只读,不可删除
5. 从作用域链中移除Result(1)
6. 返回Result(3)
官方文档读起来十分拗口。简单来说,ECMAScript是通过上下文来区分这两者的:假如 function foo(){} 是一个赋值表达式的一部分,则认为它是一个函数表达式。而如果 function foo(){} 被包含在一个函数体内,或者位于程序(的最上层)中,则将它作为一个函数声明来解析。显然,在省略标识符的情况下,“表达式” 也就只能是表达式了。
代码如下:
function foo(){}; // 声明,因为它是程序的一部分
var bar = function foo(){}; // 表达式,因为它是赋值表达(AssignmentExpression)的一部分
new function bar(){}; // 表达式,因为它是New表达式(NewExpression)的一部分
(function(){
function bar(){}; // 声明,因为它是函数体(FunctionBody)的一部分
})();
还有一种情况:
代码如下:
(function foo(){})
这种情况也是函数表达式,它被包含在一对圆括号中的函数,在其上下文环境中,()构成了一个分组操作符,而分组操作符只能包含表达式,更多的例子:
新闻热点
疑难解答
图片精选