javascript - 引用错误: can't access lexical declaration 'Foo' before initialization

标签 javascript language-lawyer standards

运行以下代码:

<!doctype html>
<html>
<head>
  <meta charset="UTF-8">
</head>
<body>
<script>
  main()
  class Foo { }
  function main() { Foo() }
</script>
</body>
</html>

生成ReferenceError:在初始化之前无法访问词法声明“Foo”(无论如何,在 Firefox 91.5.1esr 上)。

一个简单的解决方法是将类定义向上移动一行。将 class Foo 替换为 function Foo() 也将消除错误消息。将 Foo() 更改为 new Foo()没有帮助:错误仍然存​​在。

问题:是否有引用标准和/或清晰的描述来解释此行为?

最佳答案

一个是一个ClassDeclaration在规范中。这被分类为 DeclarationPart ,出于 LexicallyScopedDeclarations 的目的,它被分类为 StatementListItem .

当 block 或函数最初被评估时(在 block 中的代码实际开始运行之前),它将执行something like :

33. Let lexDeclarations be the LexicallyScopedDeclarations of code.
34. For each element d of lexDeclarations, do
  a. NOTE: A lexically declared name cannot be the same as a function/generator declaration, formal parameter, or a var name. Lexically declared names are only instantiated here but not initialized.
  b. For each element dn of the BoundNames of d, do
    i. If IsConstantDeclaration of d is true, then
      1. Perform ! lexEnv.CreateImmutableBinding(dn, true).
    ii. Else,
      1. Perform ! lexEnv.CreateMutableBinding(dn, false).

这些LexicallyScopedDeclarations是使用ES6+语法创建的标识符,并且不包括var。 (使用 var 创建的标识符被分类为 varNamesVarDeclaredNames,它们经历的过程与上面的步骤 33-34 不同。)

因此,在 block 或函数的开头,class 标识符(以及 constlet 标识符)都具有已被绑定(bind)的绑定(bind)在环境中创建,但尚未在环境中初始化。当 BindingClassDeclarationEvaluation 时发生初始化运行,它会:

5. Perform ? InitializeBoundName(className, value, env).

只有当引擎实际运行 block 或函数内的代码并遇到class SomeClassName时,才会发生这种情况。 (这与前面引用的过程是分开的,即引擎仅查看 block 的文本以获取内部声明的标识符列表。)


当一个 block 正在运行时,您尝试使用new实例化某些东西,EvaluateNew运行,其中包括:

Let constructor be ? GetValue(ref).

最终运行 GetBindingValue ,其中有:

2. If the binding for N in envRec is an uninitialized binding, throw a ReferenceError exception.

只有当 InitializeBoundName 运行时,即引擎遇到类声明时,绑定(bind)才会被初始化。

关于javascript - 引用错误: can't access lexical declaration 'Foo' before initialization,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72081570/

相关文章:

c++ - 使用临时存储区 : is it allowed? 复制可简单复制的类型

c++ - C++ 期望数组下标是什么类型?

c++ - 公共(public)图书馆的 char 或 std::string 数组?

c - 将2个字节转换为带符号的16位整数的正确方法是什么?

c++ - 类模板的友元函数是否应该成为所有实例化的友元?

c++ - 我可以在任何地方阅读 C++ 2011 FDIS 吗?

javascript - 在 D3 V4 中添加自定义画笔 handle ?

javascript - 关于javascript对象属性赋值

javascript - 获取数组的总和并在另一个函数中回调一个函数

javascript - ChartJS : Draw vertical line at data point on chart on mouseover