4

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.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
Lonnie Best
  • 9,936
  • 10
  • 57
  • 97
  • 3
    Not sure what the variables in that section of the spec are referring to exactly, but `SetIntegrityLevel(someVar, "frozen").` really sounds like it freezes the object, which will make it non-extensible (steps 12 and 14) – CertainPerformance Dec 17 '18 at 01:53
  • I don't like this array not being extensible. See why [here](https://github.com/tc39/ecma262/issues/1375). – Lonnie Best Dec 20 '18 at 21:55

1 Answers1

4

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.

Community
  • 1
  • 1
Andrew Li
  • 55,805
  • 14
  • 125
  • 143