函数分为FD (函数定义),FE(函数表达式) ,函数构造器得到的函数
(1) FD 的栗子:
function getTaste(){
.......
}
解析器遇到上面的function关键字,会解析上面的代码为函数定义的情况,凡是不符合上述格式的,会报错。
(2)FE的栗子:
var fn = function (){
......
}
解析器会把上面的function关键字解析为表达式的情况。本例中的function后面可有函数名字,但是仅限于函数定义内调用。外面调用会用fn。
var fn = function sbfn(){
......
sbfn(); //
}
把function解析为表达式的情况,有另外的栗子:
1, function () {
alert('anonymous function is called');
}();
此处为逗号运算符情况,取值逗号后面的结果undefined。
!function () {
alert('ECMAScript');
}();
此处为!运算符情况,后面结果返回undefined 。!取反,结果为true。
(3)函数构造器的栗子
其主要特点在于这种函数的[[Scope]]属性仅包含全局对象(window)
var x = 10;
function f() {
var x = 20;
var y = 30;
var bar = new Function('alert(x); alert(y);');
bar(); // 10, "y" 未定义
}
f();
顺便提醒一句,Function构造器既可使用new 关键字,也可以没有,这样说来,这些变体是等价的。
创建函数的算法
下面的伪码描述了函数创建的算法(与联合对象相关的步骤除外)。这些描述有助于你理解ECMAScript中函数对象的更多细节。这种算法适合所有的函数类型。
F = new NativeObject();
// 属性[[Class]]是"Function"
F.[[Class]] = "Function"
// 函数对象的原型是Function的原型
F.[[Prototype]] = Function.prototype
// 医用到函数自身
// 调用表达式F的时候激活[[Call]]
// 并且创建新的执行上下文
F.[[Call]] = <reference to function>
// 在对象的普通构造器里编译
// [[Construct]] 通过new关键字激活
// 并且给新对象分配内存
// 然后调用F.[[Call]]初始化作为this传递的新创建的对象
F.[[Construct]] = internalConstructor
// 当前执行上下文的作用域链
// 例如,创建F的上下文
F.[[Scope]] = activeContext.Scope
// 如果函数通过new Function(...)来创建,
// 那么
F.[[Scope]] = globalContext.Scope
// 传入参数的个数
F.length = countParameters
// F对象创建的原型
__objectPrototype = new Object();
__objectPrototype.constructor = F // {DontEnum}, 在循环里不可枚举x
F.prototype = __objectPrototype
return F
注意,F.[[Prototype]]是函数(构造器)的一个原型,F.prototype是通过这个函数创建的对象的原型(因为术语常常混乱,一些文章中F.prototype被称之为“构造器的原型”,这是不正确的)。