ECMAScript:在哪里可以找到有关let / const变量可访问性的规范

时间:2018-07-26 16:46:58

标签: javascript ecmascript-6 ecmascript-2017

ECMAScript specification内,我们可以找到明确的规范,说明为什么在创建的词法环境之外无法访问letconst BlockStatements (与用var声明的变量相反)?

如果 BlockStatements 现在创建了new lexical environments,则letconst声明不应创建可在该词法环境之外访问的变量,而应创建var变量应该。我试图了解最新的ECMAScript规范在何处确切指定了该行为。

来自13.3.1 Let and Const Declarations

  

let和const声明定义范围为运行中的执行上下文的LexicalEnvironment的变量。实例化包含变量的Lexical Environment时会创建这些变量,但是在评估该变量的LexicalBinding之前,不能以任何方式对其进行访问。

来自13.3.2 Variable Statement

  

var语句声明范围为运行中执行上下文的VariableEnvironment的变量。 Var变量在实例化其包含的词法环境时创建,并在创建时初始化为undefined。

如图所示,两个变量声明都在实例化其包含<词>词法环境时创建变量。在 BlockStatement 的情况下,这是编译器进入该块的时间。

来自8.3 Execution Contexts

  

执行上下文的LexicalEnvironment和VariableEnvironment组件始终是Lexical Environments

1 个答案:

答案 0 :(得分:4)

正如在var的描述中所见,它的范围仅限于运行中的执行上下文的VariableEnvironment。有一个顶级VariableEnvironment,然后创建了一个新的when you enter a function,然后在this part about Execution Contexts中,它说:

  

执行上下文的LexicalEnvironment和VariableEnvironment组件始终是Lexical Environments。创建执行上下文时,其LexicalEnvironment和VariableEnvironment组件最初具有相同的值。

因此,在函数开始时,LexicalEnvironment和VariableEnvironment是相同的。

然后,在13.2.13 Runtime Semantics: Evaluation Block: { }中,您可以看到进入块时创建了一个新的LexicalEnvironment,而离开块时则恢复了先前的VariableEnvironment。但是,当您进入或离开一个块时,没有提及新的let(因为该函数在函数中保持不变)。

因此,由于constvar的作用域是在声明它们的LexicalEnvironment中,并且位于某个块的本地,因此在该块之外无法访问它。

但是,VariableEnvironment的作用域是let,后者仅创建并作用于整个函数,而不是块。

constlet变量不能在其LexicalEnvironment外部访问,因为一旦执行上下文离开它们的块(一旦您离开该块,他们的LexicalEnvironment本质上是从堆栈中弹出的,不再在范围搜索链中供解释器查找变量。


在规范中添加以下内容:

  

[{constvar]变量是在实例化其包含的词法环境时创建的,但在评估该变量的LexicalBinding之前,无法以任何方式进行访问。

这意味着即使在他们的词法环境中,您也无法访问它们,直到对它们的定义求值。用外行的话来说,这意味着它们不会像let那样被提升到其作用域的顶部,因此只有在定义之后才能使用它们。这是通过在语句运行之前,不初始化const中的LexicalEnvironmentReferenceError变量来实现的,并且查找变量的GetBindingValue()操作将发现它尚未已初始化,并将抛出varundefined变量会立即初始化为ReferenceError,因此它们不会导致此let x = 3; function test() { x = 1; let x = 2; console.log("hello"); } test();

您可以在以下代码中看到它的工作原理:

let x = 3

x行,在外部LexicalEnvironment中初始化了一个变量test()

然后,当您调用x时,在该函数的开始处,将创建一个新的LexicalEnvironment,并将此块中LexicalEnvironment的新声明放入该新x = 1中,但尚未初始化。

然后,您进入x语句。解释器查找LexicalEnvironment,在当前的ReferenceError中找到它,但是它尚未初始化,因此抛出了VariableEnvironment


根据您评论中的问题:

  

我一直在颠倒规格,但是很难发现VariableEnvironments仅为函数创建。也许您可以添加一个答案,以显示要遵循上述结论所遵循的规范中的哪些步骤?

您只需遍历规范中创建{{1}}的所有地方,您会发现发生此情况的唯一地方是函数执行的开始和顶层。

例如,以下位置为PrepareForOrdinaryCall。还有一些。

但是,它从来没有描述过在块的开头发生的这种情况,而只是描述函数的开头。

这些规范的编写方式,它们描述了事情何时发生而不是什么时候不发生(这在逻辑上是合理的),但这意味着要证明某事没有发生,您必须在任何地方都找不到说确实发生了。