JavaScript中存储的命名函数表达式中标识符的不变绑定记录在哪里? [英] Where is the immutable binding record of the identifier in a named function expression stored in 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.
所以我的问题如下:
- 函数名称的不可变绑定记录存储在哪里?
- 在NFE中解析时,函数名称
foo
为何胜过var foo = 1
?它们的绑定记录是否存储在相同的词汇环境中?如果是这样,怎么办? - 函数名称
foo
在内部可访问但在外部不可见的现象背后是什么?
- Where is the immutable binding record of the function name stored?
- How come the function name
foo
outweighvar foo = 1
when resolved inside NFE? Are their binding records stored in the same lexical environment? If so, how? - 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:
- 让
funcEnv
是调用NewDeclarativeEnvironment
传递正在运行的执行上下文的词法环境作为论证 - 让
envRec
成为funcEnv
的环境记录. - 调用
CreateImmutableBinding(N)
的具体方法envRec
将函数的Identifier
作为参数传递. - 让
closure
是创建新的Function对象[…]的结果. 传递funcEnv
作为 Scope . - 调用
InitializeImmutableBinding(N,V)
的具体方法envRec
传递函数的Identifier
并将closure
作为参数. - 返回
closure
.
- Let
funcEnv
be the result of callingNewDeclarativeEnvironment
passing the running execution context’s Lexical Environment as the argument - Let
envRec
befuncEnv
’s environment record. - Call the
CreateImmutableBinding(N)
concrete method ofenvRec
passing theIdentifier
of the function as the argument. - Let
closure
be the result of creating a new Function object […]. Pass infuncEnv
as the Scope. - Call the
InitializeImmutableBinding(N,V)
concrete method ofenvRec
passing theIdentifier
of the function andclosure
as the arguments. - 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屋!