gpt4 book ai didi

JavaScript 闭包 - 使用 ECMA 规范,请解释闭包是如何创建和维护的

转载 作者:数据小太阳 更新时间:2023-10-29 06:12:27 26 4
gpt4 key购买 nike

我正在阅读 JavaScript closures .我熟悉 Execution Contexts , 如何 Lexical Environment维护的,很熟悉Lexical Scoping .

我想知道 JavaScript 中的闭包是如何创建维护的。有时,如果不了解它的实际操作方式,我很难掌握如此重要的概念。我知道,根据维基百科,闭包是

is a function or reference to a function together with a referencing environment—a table storing a reference to each of the non-local variables (also called free variables) of that function.

但我的问题是,我想知道如何,根据 ECMA Specification ,一个闭包被创建和维护。我不是在寻找闭包理论的高级解释,请在您的回答中引用 ECMA 规范。

注意:请不要认为这是重复的,除非答案解释了使用 ECMA 规范的闭包。同样,我对有人引用维基百科并举个例子不感兴趣,我想完全理解 JavaScript 是如何做到这一点的。 (我熟悉 this question on SO )。

最佳答案

根据维基百科的定义,问题中提到,闭包是一个

is a function or reference to a function together with a referencing environment—a table storing a reference to each of the non-local variables (also called free variables) of that function.

对如何维护执行上下文和词法环境的理解是众所周知的,这里的目标是了解函数何时返回,引用环境是如何维护/引用的?

让我们开始吧。

8.6.2部分在 ECMA 262 v 5 规范中,它列出了 ECMAScript 对象的内部属性。这里要指出的是表 9 中的 [[Scope]] 属性。根据这个属性的描述,描述为

A lexical environment that defines the environment in which a Function object is executed. Of the standard built-in ECMAScript objects, only Function objects implement [[Scope]].

正如我们将看到的,函数对象的 [[Scope]] 属性将始终设置为父对象的词法环境。我们在 13.2 节中看到了这一点其中讨论了创建函数对象的过程。 (请注意:此上下文中的函数对象指的是原生 ECMAScript 对象,而不是通过代码可访问的函数对象)。

创建函数时,它会将内部 [[Scope]] 属性设置为正在运行的执行上下文的 VariableEnvironment、LexicalEnvironment 或 Global Environment,具体取决于函数是否为 function declaration。 , function expression或通过 Function constructor 创建.

当控制权交给全局代码时,以及当控制权进入函数代码时,声明绑定(bind)实例化作为初始化执行上下文的一部分发生。声明绑定(bind)实例化的一部分是通过创建第 13.2 节中提到的函数对象来绑定(bind)当前上下文范围内的函数声明。下面的例子展示了这一点:

例如

  // The global execution context has already been initialized at this stage.
// Declaration binding instantiation has occurred and the function
// foo is created as a new native object with a [[Scope]] property
// having the value of the global execution context's VariableEnvironment
function foo() {
// When foo is invoked, a new execution context will be created for
// this function scope. When declaration binding instantiation occurs,
// bar will be created as a new native object with a [[Scope]] property
// having the value of the foo execution context's VariableEnvironment
function bar() {
}
bar(); // Call bar
}
foo();

另一件事是进入/创建执行上下文时发生的过程 when entering a function .以下是所发生情况的摘要。

  1. 通过内部调用 NewDeclarativeEnvironment 创建一个新的 Lexical Environment 类型。函数的 [[Scope]] 属性将被设置为外部 引用,以便维护“词法环境”链。 (请记住, [[Scope]] 属性已设置,并且将始终是父级的词法范围。另外,词法环境链是我编造的一个短语,这个概念指的是通过外部引用遍历词法环境来解析标识符,直到标识符可以解决。)
  2. 将 LexicalEnvironment 和 VariableEnvironment 设置为在步骤 1 中新创建的 Lexical Environment。
  3. Perform declaration binding instantiation.

知道函数通过内部 [[Scope]] 属性维护对其父 Lexical Environment 的引用,我们现在可以了解闭包是如何工作的。

<script>
// foo.[[Scope]] was set to the global environment during the global execution context initialization
function foo() {
var x = 1;
// bar.[[Scope]] was set to foo's lexical environment during foo's execution context initialization
function bar() {
var y = 2;
alert(x + y);
}
return bar;
}

var dummy = foo(); // Assign variable binding "dummy" to a reference of the "bar" function.
dummy(); // Calls the "bar" function code. The reference still has it's [[Scope]] property set, thus the identifier look-ups work as expected when resolving the identifiers.
alert(dummy.name); // Alerts "bar";

</script>

所以为了回答这个问题,函数父 LexicalEnvironment 通过函数的内部 [[Scope]] 属性持久化。请注意,函数内的局部变量可以在函数运行时解析,只有“自由变量”需要跟踪并由 [[Scope]] 属性完成。

注意:如果我的信息不正确,请在下方评论。

关于JavaScript 闭包 - 使用 ECMA 规范,请解释闭包是如何创建和维护的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15117687/

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