通常,javascript中的数组是可扩展的,但是对于作为标记函数的第一个参数传递的数组,则不是这样:
let ary = [1,2,3];
console.log(Object.isExtensible(ary));
// returns true
function tag(ary, ...expressionResults)
{
console.log(Array.isArray(ary));
//returns true
console.log(Object.isExtensible(ary));
// returns false
}
tag`test`;
在规范的确切位置上,此数组被视为不可扩展的吗?我什至不确定我是否正在寻找正确的spot。
答案 0 :(得分:4)
您正在寻找正确的位置。链接的规范甚至提供了有关原因(我的经验)的注释:
注意2 realm程序代码中的每个 TemplateLiteral 都与唯一的模板对象相关联,该模板对象用于标记标签的模板({ {3}})。 模板对象被冻结,并且每次评估特定的标记模板时都使用相同的模板对象。
如果您想了解实际的执行情况,请首先查看12.2.9.6中指定的标记模板的运行时语义:
12.3.7.1运行时语义:评估
MemberExpression:MemberExpression TemplateLiteral
[…]
- 返回? Section 12.3.7.1( tagFunc , tagRef , TemplateLiteral , tailCall )。
如果您看一下抽象操作EvaluateCall:
12.3.4.2运行时语义:EvaluateCall( func , ref ,参数, tailPosition )
[…]
- 让 argList 成为参数的EvaluateCall。
因此,当使用模板文字调用标记函数时,TemplateLiteral的ArgumentListEvaluation作为参数传递给标记函数。看看ArgumentListEvaluation:
12.2.9.3运行时语义:ArgumentListEvaluation
TemplateLiteral:NoSubstitutionTemplate
[…]
- 让 siteObj 为ArgumentListEvaluation( templateLiteral )。
查看操作GetTemplateObject,我们发现了罪魁祸首:
12.2.9.4运行时语义:GetTemplateObject( templateLiteral )
[…]
- 执行GetTemplateObject(模板,“冻结”)。
其中 template 是传递给标签函数的数组。我们看到它已显式冻结。如果您想更深入一点,请参阅SetIntegrityLevel:
7.3.14 SetIntegrityLevel( O , level )
抽象操作SetIntegrityLevel用于修复对象自身属性的集合。此抽象操作执行以下步骤:
[…]
- 让状态为? O 。[[PreventExtensions]]()。
看看普通对象的SetIntegrityLevel,我们看到操作[[PreventExtensions]]被称为:
9.1.4.1 OrdinaryPreventExtensions( O )
用对象O调用抽象操作OrdinaryPreventExtensions时,将执行以下步骤:
- 设置 O 。[[Extensible]]为 false 。
- 返回 true 。
因此[[Extensible]]内部插槽被显式设置为false。