JavaScript中存储的命名函数表达式中标识符的不变绑定记录在哪里? [英] Where is the immutable binding record of the identifier in a named function expression stored in JavaScript?

查看:91
本文介绍了JavaScript中存储的命名函数表达式中标识符的不变绑定记录在哪里?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近,我遇到了一些有关命名函数表达式(NFE)的有趣事实.我知道可以在函数体内访问NFE的函数名称,这使递归更加方便并节省了arguments.callee.并且功能名称在功能主体外部不可用.例如

Recently I ran into some interesting facts about named function expressions (NFE). I understand that the function name of an NFE can be accessed within the function body, which makes recursion more convenient and saves us arguments.callee. And the function name is not available outside the function body. For example,

var foo = function bar() {
    console.log(typeof bar);
}; 

typeof foo; // 'function'
typeof bar; // 'undefined', inaccessible outside the NFE
foo(); // 'function', accessible inside the NFE

这是一个有据可查的功能,而kangax具有出色的帖子关于NFE,并在那里提到了这种现象.最让我惊讶的是,NFE的函数名称不能与函数主体中的其他值重新关联.例如

This is a well-documented feature, and kangax has a wonderful post about NFE and mentioned this phenomenon there. What surprises me most is that the function name of an NFE cannot be re-associated with other values in the function body. For example,

(function foo() {
    foo = 5;
    alert(foo);
})(); // will alert function code instead of 5

在上面的示例中,我们尝试将标识符foo与另一个值5重新绑定.但这失败了!我转向ES5 Spec,发现创建了NFE时,创建了一个不可变的绑定记录并将其添加到词法环境的环境记录中.

In the above example, We tried to rebind the identifier foo with another value 5. But this fails! And I turned to ES5 Spec and found that an immutable binding record was created and added into the environment records of lexical environment when an NFE is created.

问题是,当NFE在函数主体中引用其自己的函数名称时,该名称被解析为自由变量.在上面的示例中,foo在NFE中被引用,但它既不是该函数的形式参数也不是局部变量.因此,它是一个自由变量,可以通过NFE的[[scope]]属性来解析其绑定记录.

The problem is, when an NFE refers to its own function name inside the function body, the name was resolved as a free variable. In the above example, foo is referred to inside the NFE, but it is neither a formal parameter nor a local variable of this function. So it's a free variable and its binding record can be resolved through the [[scope]] property of the NFE.

因此请考虑一下,如果在外部作用域中还有另一个具有相同名称的标识符,则似乎存在一些冲突.例如

So consider this, if we have another identifier with the same name in the outer scope, there seems to be some conflict. For example,

var foo = 1;
(function foo() {
    alert(foo);
})(); // will alert function code rather than 1
alert(foo); // 1

当我们执行NFE时,免费变量 foo被解析为其所关联的功能.但是,当控件退出NFE上下文时,foo被解析为外部作用域中的局部变量.

When we execute the NFE, the free variable foo was resolved to the function it is associated to. But when the control exits the NFE context, foo was resolved as a local variable in the outer scope.

所以我的问题如下:

  1. 函数名称的不可变绑定记录存储在哪里?
  2. 在NFE中解析时,函数名称foo为何胜过var foo = 1?它们的绑定记录是否存储在相同的词汇环境中?如果是这样,怎么办?
  3. 函数名称foo在内部可访问但在外部不可见的现象背后是什么?
  1. Where is the immutable binding record of the function name stored?
  2. How come the function name foo outweigh var foo = 1 when resolved inside NFE? Are their binding records stored in the same lexical environment? If so, how?
  3. What's behind the phenomenon that function name foo is accessible inside but invisible outside?

有人可以通过ES5规范对此有所了解吗?我在网上找不到太多讨论.

Can someone shed some light on this with ES5 spec? I don't find much discussion online.

推荐答案

函数名称的不可变绑定记录存储在哪里?

Where is the immutable binding record of the function name stored?

在一个额外的词汇环境记录中,您看不到:-)

In an extra lexical environment record that you cannot see :-)

在NFE中解析时,函数名称foo为何胜过var foo = 1?

实际上不是.您可以在函数范围内声明一个新的本地var foo,而不会发生任何冲突,但是如果不这样做,则免费的foo变量会解析为不可变的绑定.但是,它确实比作用域链中更高的全局foo变量好.

In fact it doesn't. You can declare a new local var foo in the function scope without any collisions, but if you don't then the free foo variable does resolve to the immutable binding. It does outweigh global foo variables higher in the scope chain, however.

var foo = 1;
(function foo() { "use strict";
    var foo = 2;
    console.log(foo); // 2
}());
(function foo() { "use strict";
    console.log(foo); // function …
    foo = 2; // Error: Invalid assignment in strict mode
}());

它们的绑定记录是否存储在相同的词汇环境中?

Are their binding records stored in the same lexical environment?

不.每个命名函数表达式都包含在一个额外的词法环境中,该词法环境对使用函数初始化的函数名称具有单个不变的绑定.

No. Every named function expression is enclosed in an extra lexical environment that has a single, immutable binding for the function's name initialised with the function.

在规范的功能定义(§13)部分中对此进行了描述.虽然函数声明和匿名函数表达式的步骤基本上是为 Scope 使用 current 执行上下文的词法环境,使用该函数主体创建一个新的函数对象",表达式更复杂:

This is described in the Function Definition (§13) section of the spec. While the steps for function declarations and anonymous function expressions basically are "create a new function object with that function body using the current execution context's lexical environment for the Scope", named function expressions are more complicated:

  1. funcEnv是调用 NewDeclarativeEnvironment 传递正在运行的执行上下文的词法环境作为论证
  2. envRec成为funcEnv的环境记录.
  3. 调用 CreateImmutableBinding(N) 的具体方法envRec将函数的Identifier作为参数传递.
  4. closure是创建新的Function对象[…]的结果. 传递funcEnv作为 Scope .
  5. 调用 InitializeImmutableBinding(N,V) 的具体方法envRec传递函数的Identifier并将closure作为参数.
  6. 返回closure.
  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(N) concrete method of envRec passing the Identifier of the function as the argument.
  4. Let closure be the result of creating a new Function object […]. Pass in funcEnv as the Scope.
  5. Call the InitializeImmutableBinding(N,V) concrete method of envRec passing the Identifier of the function and closure as the arguments.
  6. Return closure.

它确实为函数表达式构造了一个额外的包装器环境.在具有块作用域的ES6代码中:

It does construct an extra wrapper environment just for the function expression. In ES6 code with block scopes:

var x = function foo(){};
// is equivalent to
var x;
{
    const foo = function() {};
    x = foo;
}
// foo is not in scope here

函数名称foo在内部可访问但在外部不可见的现象背后是什么?

What's behind the phenomenon that function name foo is accessible inside but invisible outside?

foo不可变绑定不是在当前执行上下文的词法环境中创建的,而是在包装器环境中创建的,该包装器仅用于函数表达式的闭包.

The foo immutable binding is not created in the current execution context's lexical environment, but in the wrapper environment which is only used for the closure around the function expression.

这篇关于JavaScript中存储的命名函数表达式中标识符的不变绑定记录在哪里?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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