gpt4 book ai didi

javascript - 保存在 JavaScript 中的命名函数表达式中标识符的不可变绑定(bind)记录在哪里?

转载 作者:塔克拉玛干 更新时间:2023-11-02 21:16:07 24 4
gpt4 key购买 nike

最近我遇到了一些关于命名函数表达式 (NFE) 的有趣事实。我了解到,在函数体内可以访问 NFE 的函数名,这使得递归更方便,并为我们节省了 arguments.callee。并且函数名在函数体之外是不可用的。例如,

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 有一个很棒的 post关于 NFE 并在那里提到了这种现象。最让我惊讶的是,NFE 的函数名不能与函数体中的其他值重新关联。例如,

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

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

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

所以考虑一下,如果我们在外部作用域中有另一个同名的标识符,似乎会有一些冲突。例如,

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

当我们执行 NFE 时,自由变量 foo 被解析为它关联的函数。但是当控件退出 NFE 上下文时,foo 被解析为外部作用域中的局部变量。

所以我的问题如下:

  1. 函数名的不可变绑定(bind)记录存储在哪里?
  2. 在 NFE 内部解析时,函数名称 foo 为什么会超过 var foo = 1?它们的绑定(bind)记录是否存储在相同的词法环境中?如果是这样,如何?
  3. 函数名foo 内部可访问但外部不可见的现象背后是什么?

有人可以通过 ES5 规范阐明这一点吗?我在网上找不到太多讨论。

最佳答案

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

在你看不到的额外词法环境记录中:-)

How come the function name foo outweigh var foo = 1 when resolved inside NFE?

其实不然。您可以在函数作用域中声明一个新的本地 var foo 而不会发生任何冲突,但如果您不这样做,则自由的 foo 变量会解析到不可变的绑定(bind)。但是,它确实比范围链中更高的全局 foo 变量更重要。

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?

没有。每个命名的函数表达式都包含在一个额外的词法环境中,该环境具有一个单一的、不可变的函数名称绑定(bind),用函数初始化。

这在 Function Definition (§13) 中有描述规范的一部分。虽然函数声明和匿名函数表达式的步骤基本上是“使用 Scope当前执行上下文的词法环境创建一个具有该函数体的新函数对象”,命名函数表达式更复杂:

  1. funcEnv 为调用NewDeclarativeEnvironment 的结果 传递正在运行的执行上下文的 Lexical Environment作为论点
  2. envRec成为funcEnv的环境记录。
  3. 调用CreateImmutableBinding(N) envRec 的具体方法将函数的 Identifier 作为参数传递。
  4. closure 成为创建新 Function 对象 […] 的结果。 funcEnv 作为 Scope 传入。
  5. 调用InitializeImmutableBinding(N,V) envRec 的具体方法将函数的 Identifierclosure 作为参数传递。
  6. 返回闭包

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

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

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

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

关于javascript - 保存在 JavaScript 中的命名函数表达式中标识符的不可变绑定(bind)记录在哪里?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30547514/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com