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. 结束评估