Simba
Simba
JAVASCRIPT

ECMA-262 函数部分解读

ECMA-262 函数部分解读
8 min read
#Javascript

运行时语义:评估(Evaluation)

  • 不包含StatementList返回一个NormalCompletion空集合
  • 包含的情况:
  1. 首先声明一个oldEnv作为当前运行时的执行上下文的词法环境LexicalEnvironment
  2. 接着声明一个blockEnv作为创建无绑定的新声明环境NewDeclarativeEnvironment(oldEnv)
  3. 执行BlockDeclarationInstantiation(StatementList, blockEnv)
  4. 将当前运行时的执行上下文词法环境LexicalEnvironment设置为blockEnv
  5. 声明一个blockValue作为StatementList求值的结果
  6. 将当前运行时的词法环境LexicalEnvironment设置为oldEnv
  7. 返回blockValue

NOTE: 无论控制权/控件(?)如何离开BlockLexicalEnvironment 总是恢复到原来的状态

实例化声明块(BlockDeclarationInstantiation)

NOTE: 当评估一个Block或者CaseBlock时 将创建一个新的声明环境记录 并在环境记录中实例化该块中声明的每个块作用域变量、常量、函数或类的绑定

抽象操作BlockDeclarationInstantiation接受参数code(可解析的节点)、env(一个环境记录) code主要是对应与块主体的解析节点 env是要在其中所创建绑定的环境记录 调用时执行以下步骤:

  1. 断言:env是一个声明式的环境记录

  2. 声明一个declarations作为code的词汇作用域声明LexicallyScopedDeclarations

  3. 遍历declarations中的每个元素d, 执行:

a. 遍历d的绑定名称BoundsNames中每个元素dn 执行:

​ i. 如果d属于常量声明IsConstantDeclaration,接着执行!env.CreateImmutableBinding(dn, true)在环境中创建一个新的但未初始化的不可变绑定 其中dn为绑定名称

​ ii. 否则 要满足env环境记录中没有dn的绑定值env.HasBinding(dn) 才执行!env.CreateMutableBinding(dn,false)在环境中创建一个新的但未初始化的可变绑定 其中dn为绑定名称

b. 如果d时一个函数声明、生成器声明、异步函数声明、异步生成器声明 则执行:

​ i. 声明fn作为d的绑定名称中的唯一元素

​ ii. 声明fo作为d的实例化函数对象InstantiateFunctionObject参数为env

​ iii. 如果envfn的绑定是未初始化的绑定 则执行初始化绑定赋值env.InitializeBinding(fn, fo)

​ iv. 否则断言d是一个函数声明 执行进行已有绑定值的修改env.SetMutableBinding(fn, fo, false)

B.3.3 块级函数声明Web遗留兼容性语义

在ECMAScript 2015之前,ECMAScript规范没有将函数声明FunctionDeclaration的出现定义为Block语句的StatementList元素 但是对于这种形式的函数声明FunctionDeclaration的支持是一种允许的扩展 大多数浏览器托管的ECMAScript实现都允许这样做 不幸的是 这些声明的语义在这些浏览器实现之间不同 由于存在这些语义差异 因此现有的使用块级函数声明的web ECMAScript代码只能在浏览器实现之间移植,前提是其用法仅取决于所有浏览器实现对这些声明的语义交集 以下是属于该交集语义的用例:

  1. 函数被声明并且仅在单个Block中引用
  • 一个或多个绑定标识符BindingIdentifier为名称f的函数声明FunctionDeclarations出现在一个封闭函数g的函数代码中 并且该声明嵌套在一个Block
  • g的函数代码中 没有其他非var声明的f声明
  • f作为标识符引用 IdentifierReference的所有引用都出现在包含f声明的BlockStatementList
  1. 一个函数可能在一个Block中声明和使用 但也可能被不包含在同一Block中的内部函数定义引用
  • 一个或多个绑定标识符BindingIdentifier为名称f的函数声明FunctionDeclarations出现在一个封闭函数g的函数代码中 并且该声明嵌套在一个Block
  • g的函数代码中 没有其他非var声明的f声明
  • 在包含f声明的块的StatementList中,f可能作为IdentifierReference出现。
  • 在嵌套在g中的另一个函数h中 至少有一个f作为IdentifierReference出现 并且没有其他f的声明遮盖了h中对f的引用。
  • h的所有调用都发生在f的声明评估之后
  1. 函数在单个块中声明并且可能在其中使用 但也可以在后续块中引用
  • 一个或多个绑定标识符BindingIdentifier为名称f的函数声明FunctionDeclarations出现在一个封闭函数g的函数代码中 并且该声明嵌套在一个Block
  • g的函数代码中 没有其他非var声明的f声明
  • 在包含f声明的块的StatementList中,f可能作为IdentifierReference出现。
  • g的函数代码中,至少有一次出现f作为IdentifierReference 该词按词法跟随包含f的声明的Block

B.3.3.1 对函数声明实例化的更改Changes to FunctionDeclarationInstantiation

  1. 当前为非严格模式下 则

a. 对于直接包含在BlockCaseClauseDefaultClauseStatementList中的每个函数声明f 执行

​ i. 声明一个F作为f的绑定标识符BindingIdentifierStringValue

​ ii. 如果用以F作为BindingIdentifierVariableStatement代替FunctionDeclaration f不会对func产生任何早期错误 并且F不是parameterNames的元素 则

  1. 注意:Fvar绑定不是VarDeclaredName、形式参数的名称或其他FunctionDeclaration 则仅在此处实例化

  2. 如果initializedBindings不包含F 并且F不是“参数” 则

a. 执行!varEnv.CreateMutableBinding(F, false)

b. 执行varEnv.InitializeBinding(F, undefined)

c. 将F添加到instantiatedVarNames

  1. 评估FunctionDeclaration f时,请执行以下步骤,以代替15.2.6中提供的FunctionDeclaration评估算法:

a. 声明fenv作为当前执行上下文的VariableEnvironment

b. 声明benv作为当前执行上下文的LexicalEnvironment

c. 声明fobj获取!benv.GetBindingValue(F, false)LexicalEnvironmentF的返回值

d. 执行!fenv.SetMutableBinding(F, fobj, false)设置VariableEnvironment中的F

e. 结束评估