ECMA-262 函数部分解读

运行时语义:评估(Evaluation)
- 不包含
StatementList返回一个NormalCompletion空集合 - 包含的情况:
- 首先声明一个
oldEnv作为当前运行时的执行上下文的词法环境LexicalEnvironment - 接着声明一个
blockEnv作为创建无绑定的新声明环境NewDeclarativeEnvironment(oldEnv) - 执行
BlockDeclarationInstantiation(StatementList, blockEnv) - 将当前运行时的执行上下文词法环境
LexicalEnvironment设置为blockEnv - 声明一个
blockValue作为StatementList求值的结果 - 将当前运行时的词法环境
LexicalEnvironment设置为oldEnv - 返回
blockValue
NOTE: 无论控制权/控件(?)如何离开
Block、LexicalEnvironment总是恢复到原来的状态
实例化声明块(BlockDeclarationInstantiation)
NOTE: 当评估一个
Block或者CaseBlock时 将创建一个新的声明环境记录 并在环境记录中实例化该块中声明的每个块作用域变量、常量、函数或类的绑定
抽象操作BlockDeclarationInstantiation接受参数code(可解析的节点)、env(一个环境记录) code主要是对应与块主体的解析节点 env是要在其中所创建绑定的环境记录 调用时执行以下步骤:
-
断言:
env是一个声明式的环境记录 -
声明一个
declarations作为code的词汇作用域声明LexicallyScopedDeclarations -
遍历
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. 如果env中fn的绑定是未初始化的绑定 则执行初始化绑定赋值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代码只能在浏览器实现之间移植,前提是其用法仅取决于所有浏览器实现对这些声明的语义交集 以下是属于该交集语义的用例:
- 函数被声明并且仅在单个
Block中引用
- 一个或多个绑定标识符
BindingIdentifier为名称f的函数声明FunctionDeclarations出现在一个封闭函数g的函数代码中 并且该声明嵌套在一个Block中 - 在
g的函数代码中 没有其他非var声明的f声明 f作为标识符引用IdentifierReference的所有引用都出现在包含f声明的Block的StatementList中
- 一个函数可能在一个
Block中声明和使用 但也可能被不包含在同一Block中的内部函数定义引用
- 一个或多个绑定标识符
BindingIdentifier为名称f的函数声明FunctionDeclarations出现在一个封闭函数g的函数代码中 并且该声明嵌套在一个Block中 - 在
g的函数代码中 没有其他非var声明的f声明 - 在包含
f声明的块的StatementList中,f可能作为IdentifierReference出现。 - 在嵌套在
g中的另一个函数h中 至少有一个f作为IdentifierReference出现 并且没有其他f的声明遮盖了h中对f的引用。 h的所有调用都发生在f的声明评估之后
- 函数在单个块中声明并且可能在其中使用 但也可以在后续块中引用
- 一个或多个绑定标识符
BindingIdentifier为名称f的函数声明FunctionDeclarations出现在一个封闭函数g的函数代码中 并且该声明嵌套在一个Block中 - 在
g的函数代码中 没有其他非var声明的f声明 - 在包含
f声明的块的StatementList中,f可能作为IdentifierReference出现。 - 在
g的函数代码中,至少有一次出现f作为IdentifierReference该词按词法跟随包含f的声明的Block
B.3.3.1 对函数声明实例化的更改Changes to FunctionDeclarationInstantiation
- 当前为非严格模式下 则
a. 对于直接包含在Block、CaseClause或DefaultClause的StatementList中的每个函数声明f 执行
i. 声明一个F作为f的绑定标识符BindingIdentifier的StringValue
ii. 如果用以F作为BindingIdentifier的VariableStatement代替FunctionDeclaration f不会对func产生任何早期错误 并且F不是parameterNames的元素 则
-
注意:
F的var绑定不是VarDeclaredName、形式参数的名称或其他FunctionDeclaration则仅在此处实例化 -
如果
initializedBindings不包含F并且F不是“参数” 则
a. 执行!varEnv.CreateMutableBinding(F, false)
b. 执行varEnv.InitializeBinding(F, undefined)
c. 将F添加到instantiatedVarNames
- 评估
FunctionDeclaration f时,请执行以下步骤,以代替15.2.6中提供的FunctionDeclaration评估算法:
a. 声明fenv作为当前执行上下文的VariableEnvironment
b. 声明benv作为当前执行上下文的LexicalEnvironment
c. 声明fobj获取!benv.GetBindingValue(F, false)的LexicalEnvironment中F的返回值
d. 执行!fenv.SetMutableBinding(F, fobj, false)设置VariableEnvironment中的F值
e. 结束评估