ECMAScript | Определения классов (Class Definitions)

ECMAScript | Определения классов (Class Definitions)

 

Синтаксис Определения Классов

ClassDeclaration [Yield, Await, Default] :

class BindingIdentifier [?Yield, ?Await] ClassTail [?Yield, ?Await]

[+Default] class ClassTail [?Yield, ?Await]

ClassExpression [Yield, Await] :

class BindingIdentifier [?Yield, ?Await] opt ClassTail [?Yield, ?Await]

ClassTail [Yield, Await] :

ClassHeritage [?Yield, ?Await] opt { ClassBody [?Yield, ?Await] opt }

ClassHeritage [Yield, Await] :

extends LeftHandSideExpression [?Yield, ?Await]

ClassBody [Yield, Await] :

ClassElementList [?Yield, ?Await]

ClassElementList [Yield, Await] :

ClassElement [?Yield, ?Await]

ClassElementList [?Yield, ?Await] ClassElement [?Yield, ?Await]

ClassElement [Yield, Await] :

MethodDefinition [?Yield, ?Await]

static MethodDefinition [?Yield, ?Await]

FieldDefinition [?Yield, ?Await] ;

static FieldDefinition [?Yield, ?Await] ;

;

FieldDefinition [Yield, Await] :

ClassElementName [?Yield, ?Await] Initializer [+In, ?Yield, ?Await] opt

ClassElementName [Yield, Await] :

PropertyName [?Yield, ?Await]

PrivateIdentifier

 

Примечание

Определение класса — это всегда код строгого режима.

 

Статическая семантика: Ранние Ошибки — Early Errors

ClassTail : ClassHeritage opt { ClassBody }

  • Это синтаксическая ошибка, если ClassHeritage отсутствует и следующий алгоритм оценивается как истинный — true:
1. Пусть конструктором constructor будет ConstructorMethod для ClassBody.
2. Если конструктор constructor является empty (пустой), вернуть false.
3. Вернуть HasDirectSuper конструктора constructor.

ClassBody : ClassElementList

  • Это синтаксическая ошибка, если PrototypePropertyNameList из ClassElementList содержит более одного вхождения «constructor».
  • Это синтаксическая ошибка, если PrivateBoundIdentifiers из ClassElementList содержит какие-либо повторяющиеся записи, если только имя не используется один раз для получателя (геттера) и один раз для установщика (сеттера) и ни в каких других записях, а получатель и установщик либо статические, либо оба нестатические.

ClassElement : MethodDefinition

ClassElement : static MethodDefinition

ClassElement : FieldDefinition ;

  • Это синтаксическая ошибка, если PropName в FieldDefinition имеет значение «constructor».

ClassElement : static FieldDefinition ;

  • Это синтаксическая ошибка, если PropName в FieldDefinition имеет значение «prototype» или «constructor».

FieldDefinition : ClassElementName Initializer opt

  • Это синтаксическая ошибка, если присутствует Initializer и ContainsArguments для Initializer имеет значение true (истинно).
  • Это синтаксическая ошибка, если присутствует Initializer и инициализатор Initializer содержит SuperCall имеет значение true (истинно).

ClassElementName : PrivateIdentifier

 

Статическая семантика: Вид Элемента Класса — ClassElementKind

ClassElement : MethodDefinition

1. Если PropName для MethodDefinition является конструктором "constructor", вернуть ConstructorMethod.
2. Верните NonConstructorMethod.

ClassElement :

static MethodDefinition

FieldDefinition ;

static FieldDefinition ;

1. Вернуть NonConstructorMethod.

ClassElement : ;

1. Вернуть empty.

 

Статическая семантика: Метод Конструктора — ConstructorMethod

ClassElementList : ClassElement

1. Если ClassElementKind для ClassElement является ConstructorMethod, вернуть ClassElement.
2. Вернуть empty.

ClassElementList : ClassElementList ClassElement

1. Пусть head будет ConstructorMethod из ClassElementList.
2. Если head не является empty (не пуста), верните head.
3. Если ClassElementKind для ClassElement имеет значение ConstructorMethod, вернуть ClassElement.
4. Вернуть empty.
Примечание

Правила ранней ошибки Early Error гарантируют, что существует только одно определение метода с именем «constructor» (конструктор) и что оно не является свойством средства доступа или определением генератора.

 

Статическая семантика: Является Статическим? — IsStatic

ClassElement : MethodDefinition

1. Вернуть false.

ClassElement : static MethodDefinition

1. Вернуть true.

ClassElement : FieldDefinition ;

1. Вернуть false.

ClassElement : static FieldDefinition ;

1. Вернуть true.

ClassElement : ;

1. Вернуть false.

 

Статическая семантика: Элементы Не Конструктора — NonConstructorElements

ClassElementList : ClassElement

1. Если ClassElementKind из ClassElement имеет значение NonConstructorMethod, тогда
   а. Вернуть Список, единственным элементом которого является ClassElement.
2. Верните новый пустой Список.

ClassElementList : ClassElementList ClassElement

1. Пусть list будет NonConstructorElements из ClassElementList.
2. Если ClassElementKind из ClassElement имеет значение NonConstructorMethod, тогда
   а. Добавьте ClassElement в конец списка list.
3. Вернуть list.

 

Статическая семантика: Список Имен Свойств Прототипа — PrototypePropertyNameList

ClassElementList : ClassElement

1. Пусть propName будет PropName класса ClassElement.
2. Если propName является empty(пусто), вернуть новый пустой Список.
3. Если IsStatic из ClassElement является true (истинно), вернуть новый пустой Список.
4. Вернуть Список, единственным элементом которого является propName.

ClassElementList : ClassElementList ClassElement

1. Пусть list будет PrototypePropertyNameList из ClassElementList.
2. Пусть propName будет PropName класса ClassElement.
3. Если propName является empty(пусто), вернуть list.
4. Если IsStatic из ClassElement является true (истинно), вернуть list.
5. Верните конкатенацию списка из list и «propName».

 

Статическая семантика: Все Частные Идентификаторы Действительны — AllPrivateIdentifiersValid

С параметром names.

Каждая альтернатива создания грамматики в этой спецификации, которая не указана ниже, неявно имеет следующее определение AllPrivateIdentifiersValid по умолчанию:

1. Для каждого дочернего узла child этого Узла Синтаксического Анализа выполните
   а. Если дочерний элемент child является экземпляром нетерминала, то
      i. Если AllPrivateIdentifiersValid дочернего элемента child с аргументом name имеет значение false, вернуть false.
2. Вернуть true (истину).

MemberExpression : MemberExpression . PrivateIdentifier

1. Если имена names содержат строковое значение StringValue из PrivateIdentifier, тогда
   а. Вернуть AllPrivateIdentifiersValid из MemberExpression с аргументом names.
2. Вернуть false.

CallExpression : CallExpression . PrivateIdentifier

1. Если имена names содержат StringValue из PrivateIdentifier, тогда
   а. Вернуть AllPrivateIdentifiersValid из CallExpression с аргументом names.
2. Вернуть false.

OptionalChain : ?. PrivateIdentifier

1. Если имена names содержат StringValue из PrivateIdentifier, верните true.
2. Вернуть false.

OptionalChain : OptionalChain . PrivateIdentifier

1. Если имена names содержат StringValue из PrivateIdentifier, тогда
   а. Верните AllPrivateIdentifiersValid из OptionalChain с аргументом names.
2. Вернуть false.

ClassBody : ClassElementList

1. Пусть newNames будет списком конкатенации из names и PrivateBoundIdentifiers из ClassBody.
2. Верните AllPrivateIdentifiersValid из ClassElementList с аргументом newNames.

 

Статическая семантика: Идентификаторы Частных Привязок — PrivateBoundIdentifiers

FieldDefinition : ClassElementName Initializer opt

1. Вернуть PrivateBoundIdentifiers из ClassElementName.

ClassElementName : PrivateIdentifier

1. Верните Список, единственным элементом которого является строковое значение StringValue из PrivateIdentifier.

ClassElementName : PropertyName

ClassElement : ;

1. Верните новый пустой список.

ClassElementList : ClassElementList ClassElement

1. Пусть names1 будет PrivateBoundIdentifiers для ClassElementList.
2. Пусть names2 будет PrivateBoundIdentifiers класса ClassElement.
3. Вернуть конкатенацию списка из names1 и names2.

MethodDefinition :

ClassElementName ( UniqueFormalParameters ) { FunctionBody }

get ClassElementName ( ) { FunctionBody }

set ClassElementName ( PropertySetParameterList ) { FunctionBody }

GeneratorMethod :

* ClassElementName ( UniqueFormalParameters ) { GeneratorBody }

AsyncMethod :

async ClassElementName ( UniqueFormalParameters ) { AsyncFunctionBody }

AsyncGeneratorMethod :

async * ClassElementName ( UniqueFormalParameters ) { AsyncGeneratorBody }

1. Верните PrivateBoundIdentifiers для ClassElementName.

 

Статическая семантика: Содержит Аргументы — ContainsArguments

Каждая альтернатива создания грамматики в этой спецификации, которая не указана ниже, неявно имеет следующее определение ContainsArguments по умолчанию:

1. Для каждого дочернего узла child этого Узла Синтаксического Анализа выполните
   а. Если дочерний элемент child является экземпляром нетерминала, то
      i. Если ContainsArguments дочернего элемента child является true (истинно), вернуть истину true.
2. Вернуть false.

IdentifierReference : Identifier

1. Если StringValue идентификатора Identifier является "arguments", верните true.
2. Вернуть false.

FunctionDeclaration : function BindingIdentifier ( FormalParameters ) { FunctionBody }

FunctionDeclaration : function ( FormalParameters ) { FunctionBody }

FunctionExpression : function BindingIdentifier opt ( FormalParameters ) { FunctionBody }

1. Вернуть false.

MethodDefinition :

ClassElementName ( UniqueFormalParameters ) { FunctionBody }

get ClassElementName ( ) { FunctionBody }

set ClassElementName ( PropertySetParameterList ) { FunctionBody }

1. Верните ContainsArguments из ClassElementName.

GeneratorMethod : * ClassElementName ( UniqueFormalParameters ) { GeneratorBody }

1. Вернуть ContainsArguments из ClassElementName.

GeneratorDeclaration : function * BindingIdentifier ( FormalParameters ) { GeneratorBody }

GeneratorDeclaration : function * ( FormalParameters ) { GeneratorBody }

GeneratorExpression : function * BindingIdentifier opt ( FormalParameters ) { GeneratorBody }

1. Вернуть false.

AsyncMethod : async ClassElementName ( UniqueFormalParameters ) { AsyncFunctionBody }

1. Вернуть ContainsArguments из ClassElementName.

AsyncFunctionDeclaration : async function BindingIdentifier ( FormalParameters ) { AsyncFunctionBody }

AsyncFunctionDeclaration : async function ( FormalParameters ) { AsyncFunctionBody }

AsyncFunctionExpression : async function ( FormalParameters ) { AsyncFunctionBody }

AsyncFunctionExpression : async function BindingIdentifier ( FormalParameters ) { AsyncFunctionBody }

1. Вернуть false.

 

Семантика среды выполнения: Оценка Определения Поля Класса — ClassFieldDefinitionEvaluation

С параметром homeObject.

FieldDefinition : ClassElementName Initializer opt

1. Пусть имя name будет результатом вычисления ClassElementName.
2. ReturnIfAbrupt(name).
3. Если Initializer opt присутствует , тогда
   а. Пусть financialParameterList будет экземпляром производственного FormalParameters : [empty].
   b. Пусть область видимости scope будет LexicalEnvironment текущего контекста выполнения.
   c. Пусть privateScope будет PrivateEnvironment текущего контекста выполнения.
   d. Пусть sourceText будет пустой последовательностью кодовых точек Unicode.
   е. Пусть инициализатор initializer будет ! OrdinaryFunctionCreate(%Function.prototype%, sourceText, financialParameterList, Initializer, non-lexical-this, scope, privateScope).
   f. Выполните MakeMethod(initializer, homeObject).
   g. Задайте для initializer.[[ClassFieldInitializerName]] значение name.
4. Иначе,
   а. Пусть инициализатор initializer будет empty (пустым).
5. Верните Запись ClassFieldDefinition {[[Name]]: name, [[Initializer]]: initializer}.

 

Примечание

Функция, созданная для инициализатора initializer, никогда не доступна напрямую коду ECMAScript.

 

Семантика среды выполнения: Оценка Элемента Класса — ClassElementEvaluation

С параметрами object и enumerable.

ClassElement : FieldDefinition ;

ClassElement : static FieldDefinition ;

1. Вернуть ClassFieldDefinitionEvaluation из FieldDefinition с аргументом object.

ClassElement : MethodDefinition

ClassElement : static MethodDefinition

1. Вернуть MethodDefinitionEvaluation из MethodDefinition с аргументами object и enumerable.

ClassElement : ;

1. Вернуть.

 

Семантика времени выполнения: Оценка Определения Класса — ClassDefinitionEvaluation

С параметрами classBinding и className.

Примечание

Для простоты спецификации частные методы и средства доступа включены вместе с частными полями в слот [[PrivateElements]] экземпляров класса. Однако любой данный объект имеет либо все, либо ни один из частных методов и средств доступа, определенных данным классом. Эта функция была разработана таким образом, чтобы реализации могли выбрать реализацию частных методов и средств доступа с использованием стратегии, которая не требует отслеживания каждого метода или средства доступа по отдельности.

Например, реализация может напрямую связывать частные методы экземпляра с их соответствующим Частным Именем и отслеживать для каждого объекта, какие конструкторы классов запускались с этим объектом в качестве значения this. Поиск частного метода экземпляра для объекта затем состоит из проверки того, что конструктор класса, который определяет метод, был использован для инициализации объекта, а затем возвращает метод, связанный с Частным Именем.

Это отличается от закрытых полей: поскольку инициализаторы полей могут генерироваться во время создания экземпляра класса, отдельный объект может иметь некоторое надлежащее подмножество закрытых полей данного класса, и поэтому закрытые поля обычно должны отслеживаться индивидуально.

ClassTail : ClassHeritage opt { ClassBody opt }

1. Пусть env будет LexicalEnvironment текущего контекста выполнения.
2. Пусть classScope будет NewDeclarativeEnvironment(env).
3. Если classBinding не является undefined, тогда
  а. Выполните classScope.CreateImmutableBinding(classBinding, true).
4. Пусть outerPrivateEnvironment будет PrivateEnvironment текущего контекста выполнения.
5. Пусть classPrivateEnvironment будет NewPrivateEnvironment(outerPrivateEnvironment).
6. Если ClassBody opt присутствует, то
  а. Для каждой Строки dn из PrivateBoundIdentifiers класса ClassBody opt выполните
    i. Если classPrivateEnvironment.[[Names]] содержит Частное Имя, у которого [[Description]] является dn, тогда
      1. Утверждено: это возможно только для пар геттер/сеттер (получатель/установщик).
    ii. Иначе,
      1. Пусть name будет новым Частным Именем, значение [[Description]] которого равно dn.
      2. Добавьте имя name в classPrivateEnvironment.[[Names]].
7. Если ClassHeritage opt отсутствует, тогда
  а. Пусть protoParent будет %Object.prototype%.
  b. Пусть constructorParent будет %Function.prototype%.
8. Иначе,
  а. Установите для LexicalEnvironment текущего контекста выполнения значение classScope.
  b. ПРИМЕЧАНИЕ. PrivateEnvironment текущего контекста выполнения является outerPrivateEnvironment при оценке ClassHeritage.
  c. Пусть superclassRef будет результатом оценки ClassHeritage.
  d. Установите для LexicalEnvironment текущего контекста выполнения значение env.
  е. Пусть superclass будет ? GetValue(superclassRef).
  f. Если superclass является null, то
    i. Пусть protoParent имеет значение null.
    ii. Пусть constructorParent будет %Function.prototype%.
  g. В противном случае, если IsConstructor(superclass) имеет значение false, генерировать исключение TypeError.
  h. Иначе,
    i. Пусть protoParent будет ? получение Get(superclass, "prototype").
    ii. Если тип Type(protoParent) не является ни Object, ни Null, выбросить исключение TypeError.
    iii. Пусть constructorParent будет superclass.
9. Пусть proto будет ! OrdinaryObjectCreate(protoParent).
10. Если ClassBody opt отсутствует, пусть конструктор constructor будет empty(пустым).
11. В противном случае пусть конструктор constructor будет ConstructorMethod из ClassBody.
12. Установите для LexicalEnvironment текущего контекста выполнения значение classScope.
13. Установите для PrivateEnvironment текущего контекста выполнения значение classPrivateEnvironment.
14. Если конструктор constructor является empty (пустой), то
  а. Пусть defaultConstructor будет новым Абстрактным Замыканием без параметров, которое ничего не фиксирует и при вызове выполняет следующие шаги:
    i. Пусть args будет Списком аргументов, переданных этой функции [[Call]] или [[Construct]].
    ii. Если NewTarget является undefined(не определен), выбросить исключение TypeError.
    iii. Пусть F будет активным функциональным объектом.
    iv. Если F.[[ConstructorKind]] является derived (производным), то
      1. ПРИМЕЧАНИЕ. Эта ветвь ведет себя аналогично constructor(...args) { super(...args); }. Наиболее заметным отличием является то, что, хотя вышеупомянутый исходный текст ECMAScript явно вызывает метод @@iterator в %Array.prototype%, эта функция этого не делает.
      2. Пусть func будет ! F.[[GetPrototypeOf]]().
      3. Если IsConstructor(func) имеет значение false, выбросить исключение TypeError.
      4. Вернуть ? Построить Construct(func, args, NewTarget).
    v. Иначе,
      1. ПРИМЕЧАНИЕ. Эта ветвь ведет себя аналогично constructor() {}.
      2. Вернуть ? OrdinaryCreateFromConstructor(NewTarget, "%Object.prototype%").
  b. Пусть F будет ! CreateBuiltinFunction(defaultConstructor, 0, className, «[[ConstructorKind]], [[SourceText]]», текущая запись Realm, constructorParent).
15. Иначе,
  а. Пусть constructorInfo будет ! DefineMethod конструктора constructor с аргументами proto и constructorParent.
  b. Пусть F будет constructorInfo.[[Closure]].
  c. Выполнить ! MakeClassConstructor(F).
  d. Выполнить ! SetFunctionName(F, className).
16. Выполнить ! MakeConstructor(F, false, proto).
17. Если ClassHeritage opt присутствует, установите F.[[ConstructorKind]] на derived (производный).
18. Выполнить ! CreateMethodProperty(proto, "constructor", F).
19. Если ClassBody opt отсутствует, пусть элементы elements будут новым пустым Списком.
20. Иначе, пусть элементы elements будут NonConstructorElements из ClassBody.
21. Пусть instancePrivateMethods будет новым пустым списком.
22. Пусть staticPrivateMethods будет новым пустым списком.
23. Пусть instanceFields будет новым пустым списком.
24. Пусть staticFields будет новым пустым списком.
25. Для каждого ClassElement e из элементов elements выполните
  а. Если IsStatic из e является false (ложно), то
    i. Пусть field будет ClassElementEvaluation для e с аргументами proto и false.
  b. Иначе,
    i. Пусть field будет ClassElementEvaluation для e с аргументами F и false.
  c. Если поле field является внезапным завершением, то
    i. Установите для LexicalEnvironment текущего контекста выполнения значение env.
    ii. Установите для PrivateEnvironment текущего контекста выполнения значение outerPrivateEnvironment.
    iii. Вернуть завершение Completion(field).
  d. Установить поле field в field.[[Value]].
  е. Если поле field является PrivateElement, тогда
    i. Утверждено: field.[[Kind]] - это либо method (метод), либо accessor (средство доступа).
    ii. Если IsStatic из e является false (ложно), пусть контейнер container будет instancePrivateMethods.
    iii. В противном случае пусть контейнер container будет staticPrivateMethods.
    iv. Если контейнер container содержит PrivateElement, [[Key]] которого является field.[[Key]], то
      1. Пусть existing будет этим PrivateElement.
      2. Утверждено: field.[[Kind]] и existing.[[Kind]] оба являются accessor (средство доступа).
      3. Если field.[[Get]] является undefined (не определено), то
        а. Пусть combined будет PrivateElement {[[Key]]: field.[[Key]], [[Kind]]: accessor, [[Get]]: existing.[[Get]]], [[Set]]: field.[[Set]] }.
      4. Иначе,
        а. Пусть combined будет PrivateElement {[[Key]]: field.[[Key]], [[Kind]]: accessor, [[Get]]: field.[[Get]]] ", [[Set]]: existing.[[Set]] }.
      5. Заменить existing в container на combined.
    v. Иначе,
      1. Добавьте поле field в контейнер container.
  f. Иначе, если поле field является Записью ClassFieldDefinition, тогда
    i. Если IsStatic из e является false (ложно), добавьте поле field в instanceFields.
    ii. В противном случае добавьте поле field в staticFields.
26. Установите для LexicalEnvironment текущего контекста выполнения значение env.
27. Если classBinding не является undefined, тогда
  а. Выполните classScope.InitializeBinding(classBinding, F).
28. Установите для F.[[PrivateMethods]] значение instancePrivateMethods.
29. Установите F.[[Fields]] в instanceFields.
30. Для каждого метода method PrivateElement из staticPrivateMethods выполните
  а. Выполнить ! PrivateMethodOrAccessorAdd(method, F).
31. Для каждого элемента fieldRecord из staticFields выполните
  а. Пусть результатом result будет DefineField(F, fieldRecord).
  b. Если результат result является внезапным завершением, то
    i. Установите для PrivateEnvironment текущего контекста выполнения значение outerPrivateEnvironment.
    ii. Вернуть результат result.
32. Установите для PrivateEnvironment текущего контекста выполнения значение outerPrivateEnvironment.
33. Вернуть F.

 

Семантика среды выполнения: Оценка Объявления Привязки Класса — BindingClassDeclarationEvaluation

ClassDeclaration : class BindingIdentifier ClassTail

1. Пусть className будет StringValue для BindingIdentifier.
2. Пусть value будет ? ClassDefinitionEvaluation для ClassTail с аргументами className и className.
3. Установите value.[[SourceText]] на исходный текст, соответствующий ClassDeclaration.
4. Пусть env будет LexicalEnvironment текущего контекста выполнения.
5. Выполнить ? InitializeBoundName(className, value, env).
6. Вернуть value.

ClassDeclaration : class ClassTail

1. Пусть value будет ? ClassDefinitionEvaluation для ClassTail с аргументами undefined и "default".
2. Установите value.[[SourceText]] на исходный текст, соответствующий ClassDeclaration.
3. Вернуть value.
Примечание

ClassDeclaration : class ClassTail возникает только как часть ExportDeclaration, и установление его привязки обрабатывается как часть действия оценки для этого продукта. Смотри раздел 16.2.3.7.

 

Семантика времени выполнения: Оценка — Evaluation

 

ClassDeclaration : class BindingIdentifier ClassTail

1. Выполнить ? BindingClassDeclarationEvaluation этого ClassDeclaration.
2. Верните NormalCompletion(empty).
Примечание

ClassDeclaration : class ClassTail встречается только как часть ExportDeclaration и никогда не оценивается напрямую.

ClassExpression : class ClassTail

1. Пусть value будет ? ClassDefinitionEvaluation для ClassTail с аргументами undefined и "".
2. Задайте value.[[SourceText]] исходному тексту, соответствующему ClassExpression.
3. Вернуть value.

ClassExpression : class BindingIdentifier ClassTail

1. Пусть className будет StringValue для BindingIdentifier.
2. Пусть value будет ? ClassDefinitionEvaluation для ClassTail с аргументами className и className.
3. Задайте value.[[SourceText]] исходному тексту, соответствующему ClassExpression.
4. Вернуть value.

ClassElementName : PrivateIdentifier

1. Пусть privateIdentifier будет StringValue для PrivateIdentifier.
2. Пусть privateEnvRec будет PrivateEnvironment текущего контекста выполнения.
3. Пусть имена names будут privateEnvRec.[[Names]].
4. Утверждено: ровно один элемент имен names является Частным Именем, [[Description]] которого является privateIdentifier.
5. Пусть privateName будет Частным Именем в именах names, у которых [[Description]] является privateIdentifier.
6. Верните privateName.

 

Информационные ссылки

Стандарт ECMAScript — Раздел «15.7 Class Definitions» — https://tc39.es/ecma262/#sec-class-definitions