为什么匿名函数表达式和命名函数表达式的初始化如此不同? [英] Why are anonymous function expressions and named function expressions initialized so differently?

查看:36
本文介绍了为什么匿名函数表达式和命名函数表达式的初始化如此不同?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在查看第 13 节或ECMAScript 规范(第 5 版).匿名函数表达式初始化如下:

<块引用>

返回创建13.2中指定的新Function对象的结果,参数由FormalParameterListopt指定,body由FunctionBody指定.传入正在运行的执行上下文的 LexicalEnvironment 作为 Scope.如果 FunctionExpression 包含在严格代码中或其 FunctionBody 是严格代码,则将 true 作为 Strict 标志传递.

这个逻辑非常类似于函数声明的初始化方式.但是,请注意命名函数表达式的初始化有何不同.

<块引用>

  1. 让 funcEnv 成为调用 NewDeclarativeEnvironment 的结果,传递运行执行上下文的词法环境作为论证
  2. 让 envRec 成为 funcEnv 的环境记录.
  3. 调用 envRec 的 CreateImmutableBinding 具体方法,传入 Identifier 的 String 值作为参数.
  4. 让闭包是创建一个新的 Function 对象的结果,如 13.2 中指定的,参数由 FormalParameterListopt 指定和由 FunctionBody 指定的主体.传入 funcEnv 作为作用域.经过如果 FunctionExpression 包含在 Strict 标志中,则为 true严格代码或者它的 FunctionBody 是否是严格代码.
  5. 调用 envRec 的 InitializeImmutableBinding 具体方法,传入 Identifier 的 String 值和闭包作为参数.
  6. 返回关闭.

我知道命名/匿名函数表达式之间的最大区别之一是命名函数表达式可以从函数内部递归调用,但这就是我能想到的.为什么设置如此不同,为什么需要执行那些额外的步骤?

解决方案

所有跳舞"的原因很简单.

命名函数表达式的标识符需要在函数范围内可用,但不能在函数范围外.

typeof f;//不明确的(函数 f() {f 类型;//功能})();

如何使 f 在函数内可用?

您不能在外部词法环境中创建绑定,因为 f 不应该在外部可用.并且您无法在内部变量环境中创建绑定,因为……它尚未创建;该函数在实例化时尚未执行,因此 10.4.3(输入函数代码)步骤及其 NewDeclarativeEnvironment 从未发生过.

因此,这样做的方法是创建一个中间词法环境,该环境直接从当前词法环境继承",然后作为 [[Scope]] 传递给新创建的函数.

如果我们将 13 中的步骤分解为伪代码,您可以清楚地看到这一点:

//创建新的绑定层funcEnv = NewDeclarativeEnvironment(当前词法环境)envRec = funcEnv//给它函数的标识符envRec.CreateImmutableBinding(标识符)//用这个中间绑定层创建函数关闭 = CreateNewFunction(funcEnv)//将新创建的函数分配给此中间绑定层内的标识符envRec.InitializeImmutableBinding(标识符,闭包)

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

(function f(){[全局环境] <- [f:function(){}] <- [当前变量环境]})();

使用匿名函数,它看起来像这样:

(function() {[全局环境] <- [当前变量环境]})();

I'm looking at section 13 or the ECMAScript specification (v. 5). An anonymous function expression is initialized as follows:

Return the result of creating a new Function object as specified in 13.2 with parameters specified by FormalParameterListopt and body specified by FunctionBody. Pass in the LexicalEnvironment of the running execution context as the Scope. Pass in true as the Strict flag if the FunctionExpression is contained in strict code or if its FunctionBody is strict code.

this logic is very similar to how a function declaration is initialized. However, notice how different initialization of a named funciton expression is.

  1. Let funcEnv be the result of calling NewDeclarativeEnvironment passing the running execution context’s Lexical Environment as the argument
  2. Let envRec be funcEnv’s environment record.
  3. Call the CreateImmutableBinding concrete method of envRec passing the String value of Identifier as the argument.
  4. Let closure be the result of creating a new Function object as specified in 13.2 with parameters specified by FormalParameterListopt and body specified by FunctionBody. Pass in funcEnv as the Scope. Pass in true as the Strict flag if the FunctionExpression is contained in strict code or if its FunctionBody is strict code.
  5. Call the InitializeImmutableBinding concrete method of envRec passing the String value of Identifier and closure as the arguments.
  6. Return closure.

I know one of the big differences between named/anonymous function expressions is that named function expressions can be called recursively from within the function, but that's all I can think of. Why is the setup so different and why does it need to do those extra steps?

解决方案

The reason for all that "dancing" is simple.

The identifier of named function expression needs to be made available within function scope but not outside.

typeof f; // undefined

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

How do you make f available within function?

You can't create binding in the outer Lexical Environment since f shouldn't be available outside. And you can't create binding in the inner Variable Environment since... it's not yet created; the function is not yet executed at the moment of instantiation, and so 10.4.3 (Entering Function Code) step with its NewDeclarativeEnvironment has never happened.

So the way this is done is by creating an intermediate lexical environment that "inherits" directly from current one, and which is then passed as [[Scope]] into the newly created function.

You can see this clearly if we break steps in 13 into pseudo code:

// 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)

So the lexical environment within f (when resolving identifier, for example) now looks like this:

(function f(){

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

})();

With anonymous function it would look like this:

(function() {

  [global environment] <- [Current Variable Environment]

})();

这篇关于为什么匿名函数表达式和命名函数表达式的初始化如此不同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆