标签功能无法扩展数组参数

时间:2018-12-17 01:41:44

标签: javascript ecmascript-6 tagged-templates ecmascript-2018

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

1 个答案:

答案 0 :(得分:4)

您正在寻找正确的位置。链接的规范甚至提供了有关原因(我的经验)的注释:

  

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

如果您想了解实际的执行情况,请首先查看12.2.9.6中指定的标记模板的运行时语义:

  

12.3.7.1运行时语义:评估

     

MemberExpression:MemberExpression TemplateLiteral

     

[…]

     
      
  1. 返回? Section 12.3.7.1 tagFunc tagRef TemplateLiteral tailCall )。
  2.   

如果您看一下抽象操作EvaluateCall

  

12.3.4.2运行时语义:EvaluateCall( func ref 参数 tailPosition

     

[…]

     
      
  1. argList 成为参数EvaluateCall
  2.   

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

  

12.2.9.3运行时语义:ArgumentListEvaluation

     

TemplateLiteral:NoSubstitutionTemplate

     

[…]

     
      
  1. siteObj ArgumentListEvaluation templateLiteral )。
  2.   

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

  

12.2.9.4运行时语义:GetTemplateObject( templateLiteral

     

[…]

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

其中 template 是传递给标签函数的数组。我们看到它已显式冻结。如果您想更深入一点,请参阅SetIntegrityLevel

  

7.3.14 SetIntegrityLevel( O level

     

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

     

[…]

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

看看普通对象的SetIntegrityLevel,我们看到操作[[PreventExtensions]]被称为:

  

9.1.4.1 OrdinaryPreventExtensions( O

     

用对象O调用抽象操作OrdinaryPreventExtensions时,将执行以下步骤:

     
      
  1. 设置 O 。[[Extensible]]为 false
  2.   
  3. 返回 true
  4.   

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