4

通常,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`;

确切地说,在规范中,这个数组被认为是不可扩展的?我什至不确定我是否正在寻找正确的位置

4

1 回答 1

4

你找对地方了。链接的规范甚至提供了关于原因的注释(emp. mine):

注 2领域的程序代码中的每个TemplateLiteral都与一个唯一的模板对象相关联,该模板对象用于评估标记模板 ( 12.2.9.6 )。模板对象被冻结,并且每次评估特定标记模板时使用相同的模板对象。

如果你想了解实际的执行,首先查看第 12.3.7.1 节中指定的标记模板的运行时语义:

12.3.7.1 运行时语义:评估

MemberExpression: MemberExpression TemplateLiteral

[…]

  1. 返回 ?EvaluateCall ( tagFunc , tagRef , TemplateLiteral , tailCall )。

如果您看一下抽象操作EvaluateCall

12.3.4.2 运行时语义:EvaluateCall ( func , ref , arguments , tailPosition )

[…]

  1. argListArgumentListEvaluationarguments

因此,当使用模板文字调用标记函数时,TemplateLiteral 的 ArgumentListEvaluation 作为参数传递给标记函数。看看ArgumentListEvaluation

12.2.9.3 运行时语义:ArgumentListEvaluation

模板字面量:NoSubstitutionTemplate

[…]

  1. siteObjGetTemplateObject ( templateLiteral )。

查看操作GetTemplateObject,我们看到了罪魁祸首:

12.2.9.4 运行时语义:GetTemplateObject ( templateLiteral )

[…]

  1. 执行SetIntegrityLevel模板,“冻结”)。

其中模板是传递给标记函数的数组。我们看到它被明确地冻结了。如果您想更深入地了解,请参阅SetIntegrityLevel

7.3.14 设置完整性级别(O级别

抽象操作 SetIntegrityLevel 用于固定对象自身属性的集合。此抽象操作执行以下步骤:

[…]

  1. 状态成为?O .[[PreventExtensions]]()。

再看一下普通对象的[[PreventExtensions]] ,我们看到调用了操作OrdinaryPreventExtensions

9.1.4.1 普通预防扩展(O

当用Object O调用抽象操作OrdinaryPreventExtensions时,采取以下步骤:

  1. O .[[Extensible]] 设置为false
  2. 返回

因此 [[Extensible]] 内部插槽被显式设置为 false。

于 2018-12-17T02:08:50.783 回答