你找对地方了。链接的规范甚至提供了关于原因的注释(emp. mine):
注 2领域的程序代码中的每个TemplateLiteral都与一个唯一的模板对象相关联,该模板对象用于评估标记模板 ( 12.2.9.6 )。模板对象被冻结,并且每次评估特定标记模板时使用相同的模板对象。
如果你想了解实际的执行,首先查看第 12.3.7.1 节中指定的标记模板的运行时语义:
12.3.7.1 运行时语义:评估
MemberExpression: MemberExpression TemplateLiteral
[…]
- 返回 ?EvaluateCall ( tagFunc , tagRef , TemplateLiteral , tailCall )。
如果您看一下抽象操作EvaluateCall:
12.3.4.2 运行时语义:EvaluateCall ( func , ref , arguments , tailPosition )
[…]
- 设argList为ArgumentListEvaluation的arguments。
因此,当使用模板文字调用标记函数时,TemplateLiteral 的 ArgumentListEvaluation 作为参数传递给标记函数。看看ArgumentListEvaluation:
12.2.9.3 运行时语义:ArgumentListEvaluation
模板字面量:NoSubstitutionTemplate
[…]
- 让siteObj为GetTemplateObject ( templateLiteral )。
查看操作GetTemplateObject,我们看到了罪魁祸首:
12.2.9.4 运行时语义:GetTemplateObject ( templateLiteral )
[…]
- 执行SetIntegrityLevel(模板,“冻结”)。
其中模板是传递给标记函数的数组。我们看到它被明确地冻结了。如果您想更深入地了解,请参阅SetIntegrityLevel:
7.3.14 设置完整性级别(O,级别)
抽象操作 SetIntegrityLevel 用于固定对象自身属性的集合。此抽象操作执行以下步骤:
[…]
- 让状态成为?O .[[PreventExtensions]]()。
再看一下普通对象的[[PreventExtensions]] ,我们看到调用了操作OrdinaryPreventExtensions:
9.1.4.1 普通预防扩展(O)
当用Object O调用抽象操作OrdinaryPreventExtensions时,采取以下步骤:
- 将O .[[Extensible]] 设置为false。
- 返回真。
因此 [[Extensible]] 内部插槽被显式设置为 false。