匿名函数表达式和命名的函数表达式为什么初始化如此不同?(Why are anonymous func

2019-08-17 05:23发布

我期待在第13或ECMAScript规范(第5)。 匿名函数表达式被初始化为如下:

返回如在13.2与由函数体指定由FormalParameterListopt指定的参数和主体中指定创建一个新的功能对象的结果。 在传递的范围运行的执行上下文的LexicalEnvironment。 如果FunctionExpression包含在严格的代码,或者如果它的函数体是严格的代码传入true作为严格的标志。

这个逻辑是非常相似的一个函数声明是如何初始化。 但是,请注意的命名功能可按表情是多么不同的初始化。

  1. 让funcEnv是调用NewDeclarativeEnvironment传递运行的执行上下文的词法环境为参数的结果
  2. 令envRec funcEnv的环境记录。
  3. 调用envRec的CreateImmutableBinding具体方法传递标识的字符串值作为参数。
  4. 让闭合是如在13.2与由函数体指定由FormalParameterListopt指定的参数和主体中指定创建一个新的功能对象的结果。 在funcEnv传递为Scope。 如果FunctionExpression包含在严格的代码,或者如果它的函数体是严格的代码传入true作为严格的标志。
  5. 调用envRec的InitializeImmutableBinding具体方法传递标识的字符串值,然后关闭作为参数。
  6. 返回关闭。

我知道的名为/匿名函数表达式之间的巨大差异之一就是有名函数表达式可以递归从函数中调用,但是这是所有我能想到的。 为什么设置如此不同?它为什么要做这些额外的步骤是什么?

Answer 1:

其原因为所有“跳舞”很简单。

需要被功能范围,而内不被外部提供命名的函数表达的标识符。

typeof f; // undefined

(function f() {
  typeof f; // function
})();

你如何f函数中使用?

您不能创建在外部词法环境的结合,因为f不应该可用之外。 你不能创建在内部环境的变量,因为......它尚未创建结合; 该功能尚未在实例化的时刻执行,所以10.4.3(进入功能码)的步骤,其NewDeclarativeEnvironment从来没有发生过。

所以这样做的方式是通过创建一个中间词法环境从当前一个“继承”是直接的,然后将其作为[[范围]]到新创建的功能通过。

你可以清楚地看到这一点,如果我们打破13个步骤为伪代码:

// create new binding layer
funcEnv = NewDeclarativeEnvironment(current Lexical Environment)

envRec = funcEnv
// give it function's identifier
envRec.CreateImmutableBinding(Identifier)

// create function with this intermediate binding layer
closure = CreateNewFunction(funcEnv)

// assign newly created function to an identifier within this intermediate binding layer
envRec.InitializeImmutableBinding(Identifier, closure)

所以内词法环境f (解析标识符时,例如)现在看起来是这样的:

(function f(){

  [global environment] <- [f: function(){}] <- [Current Variable Environment]

})();

匿名函数会是这样的:

(function() {

  [global environment] <- [Current Variable Environment]

})();


Answer 2:

与两笔交易之间的核心差异作用域(虽然,如果不出意外,这是好奇,想看看实际有多少参与这样做;) - 和你在指出一个名为/匿名函数expresssions之间的主要区别在于已经是正确的便于调用命名者递归的。

为什么这样说呢缓解 ? 好吧,其实没有什么阻止你递归调用匿名函数 ,但它只是普通的不漂亮:

//silly factorial, 5!
(function(n) {
  if (n<=1) return 1;
  return (n*arguments.callee(n-1)); //arguments.callee is so 1990s!
})(5);

事实上,这正是MDN说的话来描述命名函数表达式 !

如果你想引用函数体内的当前功能,你需要创建一个名为函数表达式。 这个名字是那么当地只有函数体(范围)。 这也避免使用非标准arguments.callee属性。



文章来源: Why are anonymous function expressions and named function expressions initialized so differently?