ECMAScript技术疑问:VarScopedDeclarations是否返回FunctionDeclaration?
背景
我正在研读ECMAScript规范,试图理解简单脚本从启动到执行完毕的完整求值流程。结合此前的问答内容,我梳理了**GlobalDeclarationInstantiation(全局声明实例化)**的流程,目标是搞清楚FunctionDeclaration(函数声明)如何被实例化(将标识符添加至全局环境记录GER)并完成初始化(为GER中的标识符赋值)。
过程中我注意到GlobalDeclarationInstantiation的第5步:
Let varDeclarations be the VarScopedDeclarations of script.
查看**VarScopedDeclarations(变量作用域声明)**的定义后,我发现它似乎从不返回FunctionDeclaration的解析节点。实际上,除了VarDeclarations(变量声明)外,它对所有语法符号都返回空列表,也就是说它仅返回带var关键字的声明对应的解析节点。例如var a = 5的VarScopedDeclarations会返回包含a = 5的解析节点。
疑问
- VarScopedDeclarations是否会返回FunctionDeclaration的解析节点?
- 如果不会,那么GlobalDeclarationInstantiation第8.1.i步中的断言(
i. Assert: d is either a FunctionDeclaration...)是否有可能成立? - 既然VarScopedDeclarations对多数符号都返回空列表,规范制定者为何还要将它们纳入?仅保留实际会返回解析节点的符号是否更简洁?LexicallyScopedDeclarations(词法作用域声明)及其他部分操作也存在同样情况。
解答
1. VarScopedDeclarations不会返回FunctionDeclaration的解析节点
根据ECMAScript规范的静态语义定义,VarScopedDeclarations仅收集var相关声明(包括变量声明、for绑定等)对应的解析节点。FunctionDeclaration属于词法作用域声明的范畴,不会被VarScopedDeclarations收集。
2. 断言可以成立,因为它处理的是合并后的声明列表
你提到的第8.1.i步断言,针对的是合并后的声明集合,而非单独的varDeclarations。在GlobalDeclarationInstantiation流程中,规范会先将functionDeclarations(从LexicallyScopedDeclarations中筛选出的函数声明)与varDeclarations合并为一个新列表declarations,后续遍历处理的正是这个合并后的列表。当遍历到来自functionDeclarations的元素时,断言d is either a FunctionDeclaration...自然成立。
3. 保留全量语法符号是为了规范的严谨性与一致性
规范为所有语法符号定义VarScopedDeclarations(以及LexicallyScopedDeclarations)的返回值,核心原因是保证静态语义规则的完整性与通用性:
- 语法本身是递归定义的,静态语义规则需要覆盖所有可能的语法节点,避免出现未定义的边界情况;
- 统一的规则结构让规范更易维护,新增语法特性时只需扩展对应规则,无需修改整体框架;
- 即使部分符号返回空列表,也明确了它们不属于变量作用域声明的范畴,消除歧义。这种设计是规范编写的通用模式,确保语义定义严谨、无遗漏。
内容的提问来源于stack exchange,提问作者Magnus

