Array Argument not Extensible in Tag Function

186 Views Asked by At

Typically, arrays in javascript are extensible, but this is not true for the array passed as the first argument of a tag function:

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`;

Where, exactly, in the specification, is this array deemed non-extensible? I'm not even sure if I'm looking at the right spot.

1

There are 1 best solutions below

1
On BEST ANSWER

You were looking in the right spot. The linked spec even offers a note as to why (emp. mine):

NOTE 2 Each TemplateLiteral in the program code of a realm is associated with a unique template object that is used in the evaluation of tagged Templates (12.2.9.6). The template objects are frozen and the same template object is used each time a specific tagged Template is evaluated.

If you want to understand the actual execution, first look at the tagged templates' runtime semantics are specified in Section 12.3.7.1:

12.3.7.1 Runtime Semantics: Evaluation

MemberExpression: MemberExpression TemplateLiteral

[…]

  1. Return ? EvaluateCall(tagFunc, tagRef, TemplateLiteral, tailCall).

If you take a look at abstract operation EvaluateCall:

12.3.4.2 Runtime Semantics: EvaluateCall (func, ref, arguments, tailPosition)

[…]

  1. Let argList be ArgumentListEvaluation of arguments.

So, when calling a tag function with a template literal, the ArgumentListEvaluation of the TemplateLiteral is passed as the argument to the tag function. Taking a look at ArgumentListEvaluation:

12.2.9.3 Runtime Semantics: ArgumentListEvaluation

TemplateLiteral: NoSubstitutionTemplate

[…]

  1. Let siteObj be GetTemplateObject(templateLiteral).

Looking at operation GetTemplateObject, we see the culprit:

12.2.9.4 Runtime Semantics: GetTemplateObject (templateLiteral)

[…]

  1. Perform SetIntegrityLevel(template, "frozen").

Where template is array passed to the tag function. We see that it's explicitly frozen. If you want to go a level deeper, see SetIntegrityLevel:

7.3.14 SetIntegrityLevel (O, level)

The abstract operation SetIntegrityLevel is used to fix the set of own properties of an object. This abstract operation performs the following steps:

[…]

  1. Let status be ? O.[[PreventExtensions]]().

And taking a look at [[PreventExtensions]] of an ordinary object, we see that operation OrdinaryPreventExtensions is called:

9.1.4.1 OrdinaryPreventExtensions (O)

When the abstract operation OrdinaryPreventExtensions is called with Object O, the following steps are taken:

  1. Set O.[[Extensible]] to false.
  2. Return true.

So the [[Extensible]] internal slot is explicitly set to false.