ECMAScript® 2024 Language Specification

Draft ECMA-262 / February 15, 2024

15.7 Class Definitions

Syntax

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] ; ClassStaticBlock ; FieldDefinition[Yield, Await] : ClassElementName[?Yield, ?Await] Initializer[+In, ?Yield, ?Await]opt ClassElementName[Yield, Await] : PropertyName[?Yield, ?Await] PrivateIdentifier ClassStaticBlock : static { ClassStaticBlockBody } ClassStaticBlockBody : ClassStaticBlockStatementList ClassStaticBlockStatementList : StatementList[~Yield, +Await, ~Return]opt Note

A class definition is always strict mode code.

15.7.1 Static Semantics: Early Errors

ClassTail : ClassHeritageopt { ClassBody } ClassBody : ClassElementList ClassElement : MethodDefinition ClassElement : static MethodDefinition ClassElement : FieldDefinition ; ClassElement : static FieldDefinition ; FieldDefinition : ClassElementName Initializeropt ClassElementName : PrivateIdentifier ClassStaticBlockBody : ClassStaticBlockStatementList

15.7.2 Static Semantics: ClassElementKind

The syntax-directed operation ClassElementKind takes no arguments and returns constructor-method, non-constructor-method, or empty. It is defined piecewise over the following productions:

ClassElement : MethodDefinition
  1. If PropName of MethodDefinition is "constructor", return constructor-method.
  2. Return non-constructor-method.
ClassElement : static MethodDefinition FieldDefinition ; static FieldDefinition ;
  1. Return non-constructor-method.
ClassElement : ClassStaticBlock
  1. Return non-constructor-method.
ClassElement : ;
  1. Return empty.

15.7.3 Static Semantics: ConstructorMethod

The syntax-directed operation ConstructorMethod takes no arguments and returns a ClassElement Parse Node or empty. It is defined piecewise over the following productions:

ClassElementList : ClassElement
  1. If ClassElementKind of ClassElement is constructor-method, return ClassElement.
  2. Return empty.
ClassElementList : ClassElementList ClassElement
  1. Let head be ConstructorMethod of ClassElementList.
  2. If head is not empty, return head.
  3. If ClassElementKind of ClassElement is constructor-method, return ClassElement.
  4. Return empty.
Note

Early Error rules ensure that there is only one method definition named "constructor" and that it is not an accessor property or generator definition.

15.7.4 Static Semantics: IsStatic

The syntax-directed operation IsStatic takes no arguments and returns a Boolean. It is defined piecewise over the following productions:

ClassElement : MethodDefinition
  1. Return false.
ClassElement : static MethodDefinition
  1. Return true.
ClassElement : FieldDefinition ;
  1. Return false.
ClassElement : static FieldDefinition ;
  1. Return true.
ClassElement : ClassStaticBlock
  1. Return true.
ClassElement : ;
  1. Return false.

15.7.5 Static Semantics: NonConstructorElements

The syntax-directed operation NonConstructorElements takes no arguments and returns a List of ClassElement Parse Nodes. It is defined piecewise over the following productions:

ClassElementList : ClassElement
  1. If ClassElementKind of ClassElement is non-constructor-method, then
    1. Return « ClassElement ».
  2. Return a new empty List.
ClassElementList : ClassElementList ClassElement
  1. Let list be NonConstructorElements of ClassElementList.
  2. If ClassElementKind of ClassElement is non-constructor-method, then
    1. Append ClassElement to the end of list.
  3. Return list.

15.7.6 Static Semantics: PrototypePropertyNameList

The syntax-directed operation PrototypePropertyNameList takes no arguments and returns a List of property keys. It is defined piecewise over the following productions:

ClassElementList : ClassElement
  1. Let propName be PropName of ClassElement.
  2. If propName is empty, return a new empty List.
  3. If IsStatic of ClassElement is true, return a new empty List.
  4. Return « propName ».
ClassElementList : ClassElementList ClassElement
  1. Let list be PrototypePropertyNameList of ClassElementList.
  2. Let propName be PropName of ClassElement.
  3. If propName is empty, return list.
  4. If IsStatic of ClassElement is true, return list.
  5. Return the list-concatenation of list and « propName ».

15.7.7 Static Semantics: AllPrivateIdentifiersValid

The syntax-directed operation AllPrivateIdentifiersValid takes argument names (a List of Strings) and returns a Boolean.

Every grammar production alternative in this specification which is not listed below implicitly has the following default definition of AllPrivateIdentifiersValid:

  1. For each child node child of this Parse Node, do
    1. If child is an instance of a nonterminal, then
      1. If AllPrivateIdentifiersValid of child with argument names is false, return false.
  2. Return true.
MemberExpression : MemberExpression . PrivateIdentifier
  1. If names contains the StringValue of PrivateIdentifier, then
    1. Return AllPrivateIdentifiersValid of MemberExpression with argument names.
  2. Return false.
CallExpression : CallExpression . PrivateIdentifier
  1. If names contains the StringValue of PrivateIdentifier, then
    1. Return AllPrivateIdentifiersValid of CallExpression with argument names.
  2. Return false.
OptionalChain : ?. PrivateIdentifier
  1. If names contains the StringValue of PrivateIdentifier, return true.
  2. Return false.
OptionalChain : OptionalChain . PrivateIdentifier
  1. If names contains the StringValue of PrivateIdentifier, then
    1. Return AllPrivateIdentifiersValid of OptionalChain with argument names.
  2. Return false.
ClassBody : ClassElementList
  1. Let newNames be the list-concatenation of names and PrivateBoundIdentifiers of ClassBody.
  2. Return AllPrivateIdentifiersValid of ClassElementList with argument newNames.
RelationalExpression : PrivateIdentifier in ShiftExpression
  1. If names contains the StringValue of PrivateIdentifier, then
    1. Return AllPrivateIdentifiersValid of ShiftExpression with argument names.
  2. Return false.

15.7.8 Static Semantics: PrivateBoundIdentifiers

The syntax-directed operation PrivateBoundIdentifiers takes no arguments and returns a List of Strings. It is defined piecewise over the following productions:

FieldDefinition : ClassElementName Initializeropt
  1. Return PrivateBoundIdentifiers of ClassElementName.
ClassElementName : PrivateIdentifier
  1. Return a List whose sole element is the StringValue of PrivateIdentifier.
ClassElementName : PropertyName ClassElement : ClassStaticBlock ;
  1. Return a new empty List.
ClassElementList : ClassElementList ClassElement
  1. Let names1 be PrivateBoundIdentifiers of ClassElementList.
  2. Let names2 be PrivateBoundIdentifiers of ClassElement.
  3. Return the list-concatenation of names1 and 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. Return PrivateBoundIdentifiers of ClassElementName.

15.7.9 Static Semantics: ContainsArguments

The syntax-directed operation ContainsArguments takes no arguments and returns a Boolean.

Every grammar production alternative in this specification which is not listed below implicitly has the following default definition of ContainsArguments:

  1. For each child node child of this Parse Node, do
    1. If child is an instance of a nonterminal, then
      1. If ContainsArguments of child is true, return true.
  2. Return false.
IdentifierReference : Identifier
  1. If the StringValue of Identifier is "arguments", return true.
  2. Return false.
FunctionDeclaration : function BindingIdentifier ( FormalParameters ) { FunctionBody } function ( FormalParameters ) { FunctionBody } FunctionExpression : function BindingIdentifieropt ( FormalParameters ) { FunctionBody } GeneratorDeclaration : function * BindingIdentifier ( FormalParameters ) { GeneratorBody } function * ( FormalParameters ) { GeneratorBody } GeneratorExpression : function * BindingIdentifieropt ( FormalParameters ) { GeneratorBody } AsyncGeneratorDeclaration : async function * BindingIdentifier ( FormalParameters ) { AsyncGeneratorBody } async function * ( FormalParameters ) { AsyncGeneratorBody } AsyncGeneratorExpression : async function * BindingIdentifieropt ( FormalParameters ) { AsyncGeneratorBody } AsyncFunctionDeclaration : async function BindingIdentifier ( FormalParameters ) { AsyncFunctionBody } async function ( FormalParameters ) { AsyncFunctionBody } AsyncFunctionExpression : async function BindingIdentifieropt ( FormalParameters ) { AsyncFunctionBody }
  1. Return false.
MethodDefinition : ClassElementName ( UniqueFormalParameters ) { FunctionBody } get ClassElementName ( ) { FunctionBody } set ClassElementName ( PropertySetParameterList ) { FunctionBody } GeneratorMethod : * ClassElementName ( UniqueFormalParameters ) { GeneratorBody } AsyncGeneratorMethod : async * ClassElementName ( UniqueFormalParameters ) { AsyncGeneratorBody } AsyncMethod : async ClassElementName ( UniqueFormalParameters ) { AsyncFunctionBody }
  1. Return ContainsArguments of ClassElementName.

15.7.10 Runtime Semantics: ClassFieldDefinitionEvaluation

The syntax-directed operation ClassFieldDefinitionEvaluation takes argument homeObject (an Object) and returns either a normal completion containing a ClassFieldDefinition Record or an abrupt completion. It is defined piecewise over the following productions:

FieldDefinition : ClassElementName Initializeropt
  1. Let name be ? Evaluation of ClassElementName.
  2. If Initializer is present, then
    1. Let formalParameterList be an instance of the production FormalParameters : [empty] .
    2. Let env be the LexicalEnvironment of the running execution context.
    3. Let privateEnv be the running execution context's PrivateEnvironment.
    4. Let sourceText be the empty sequence of Unicode code points.
    5. Let initializer be OrdinaryFunctionCreate(%Function.prototype%, sourceText, formalParameterList, Initializer, non-lexical-this, env, privateEnv).
    6. Perform MakeMethod(initializer, homeObject).
    7. Set initializer.[[ClassFieldInitializerName]] to name.
  3. Else,
    1. Let initializer be empty.
  4. Return the ClassFieldDefinition Record { [[Name]]: name, [[Initializer]]: initializer }.
Note
The function created for initializer is never directly accessible to ECMAScript code.

15.7.11 Runtime Semantics: ClassStaticBlockDefinitionEvaluation

The syntax-directed operation ClassStaticBlockDefinitionEvaluation takes argument homeObject (an Object) and returns a ClassStaticBlockDefinition Record. It is defined piecewise over the following productions:

ClassStaticBlock : static { ClassStaticBlockBody }
  1. Let lex be the running execution context's LexicalEnvironment.
  2. Let privateEnv be the running execution context's PrivateEnvironment.
  3. Let sourceText be the empty sequence of Unicode code points.
  4. Let formalParameters be an instance of the production FormalParameters : [empty] .
  5. Let bodyFunction be OrdinaryFunctionCreate(%Function.prototype%, sourceText, formalParameters, ClassStaticBlockBody, non-lexical-this, lex, privateEnv).
  6. Perform MakeMethod(bodyFunction, homeObject).
  7. Return the ClassStaticBlockDefinition Record { [[BodyFunction]]: bodyFunction }.
Note
The function bodyFunction is never directly accessible to ECMAScript code.

15.7.12 Runtime Semantics: EvaluateClassStaticBlockBody

The syntax-directed operation EvaluateClassStaticBlockBody takes argument functionObject (an ECMAScript function object) and returns either a normal completion containing an ECMAScript language value or an abrupt completion. It is defined piecewise over the following productions:

ClassStaticBlockBody : ClassStaticBlockStatementList
  1. Assert: functionObject is a synthetic function created by ClassStaticBlockDefinitionEvaluation step 5.
  2. Perform ! FunctionDeclarationInstantiation(functionObject, « »).
  3. Return ? Evaluation of ClassStaticBlockStatementList.

15.7.13 Runtime Semantics: ClassElementEvaluation

The syntax-directed operation ClassElementEvaluation takes argument object (an Object) and returns either a normal completion containing either a ClassFieldDefinition Record, a ClassStaticBlockDefinition Record, a PrivateElement, or unused, or an abrupt completion. It is defined piecewise over the following productions:

ClassElement : FieldDefinition ; static FieldDefinition ;
  1. Return ? ClassFieldDefinitionEvaluation of FieldDefinition with argument object.
ClassElement : MethodDefinition static MethodDefinition
  1. Return ? MethodDefinitionEvaluation of MethodDefinition with arguments object and false.
ClassElement : ClassStaticBlock
  1. Return ClassStaticBlockDefinitionEvaluation of ClassStaticBlock with argument object.
ClassElement : ;
  1. Return unused.

15.7.14 Runtime Semantics: ClassDefinitionEvaluation

The syntax-directed operation ClassDefinitionEvaluation takes arguments classBinding (a String or undefined) and className (a property key or a Private Name) and returns either a normal completion containing a function object or an abrupt completion.

Note

For ease of specification, private methods and accessors are included alongside private fields in the [[PrivateElements]] slot of class instances. However, any given object has either all or none of the private methods and accessors defined by a given class. This feature has been designed so that implementations may choose to implement private methods and accessors using a strategy which does not require tracking each method or accessor individually.

For example, an implementation could directly associate instance private methods with their corresponding Private Name and track, for each object, which class constructors have run with that object as their this value. Looking up an instance private method on an object then consists of checking that the class constructor which defines the method has been used to initialize the object, then returning the method associated with the Private Name.

This differs from private fields: because field initializers can throw during class instantiation, an individual object may have some proper subset of the private fields of a given class, and so private fields must in general be tracked individually.

It is defined piecewise over the following productions:

ClassTail : ClassHeritageopt { ClassBodyopt }
  1. Let env be the LexicalEnvironment of the running execution context.
  2. Let classEnv be NewDeclarativeEnvironment(env).
  3. If classBinding is not undefined, then
    1. Perform ! classEnv.CreateImmutableBinding(classBinding, true).
  4. Let outerPrivateEnvironment be the running execution context's PrivateEnvironment.
  5. Let classPrivateEnvironment be NewPrivateEnvironment(outerPrivateEnvironment).
  6. If ClassBody is present, then
    1. For each String dn of the PrivateBoundIdentifiers of ClassBody, do
      1. If classPrivateEnvironment.[[Names]] contains a Private Name pn such that pn.[[Description]] is dn, then
        1. Assert: This is only possible for getter/setter pairs.
      2. Else,
        1. Let name be a new Private Name whose [[Description]] is dn.
        2. Append name to classPrivateEnvironment.[[Names]].
  7. If ClassHeritage is not present, then
    1. Let protoParent be %Object.prototype%.
    2. Let constructorParent be %Function.prototype%.
  8. Else,
    1. Set the running execution context's LexicalEnvironment to classEnv.
    2. NOTE: The running execution context's PrivateEnvironment is outerPrivateEnvironment when evaluating ClassHeritage.
    3. Let superclassRef be Completion(Evaluation of ClassHeritage).
    4. Set the running execution context's LexicalEnvironment to env.
    5. Let superclass be ? GetValue(? superclassRef).
    6. If superclass is null, then
      1. Let protoParent be null.
      2. Let constructorParent be %Function.prototype%.
    7. Else if IsConstructor(superclass) is false, then
      1. Throw a TypeError exception.
    8. Else,
      1. Let protoParent be ? Get(superclass, "prototype").
      2. If protoParent is not an Object and protoParent is not null, throw a TypeError exception.
      3. Let constructorParent be superclass.
  9. Let proto be OrdinaryObjectCreate(protoParent).
  10. If ClassBody is not present, let constructor be empty.
  11. Else, let constructor be ConstructorMethod of ClassBody.
  12. Set the running execution context's LexicalEnvironment to classEnv.
  13. Set the running execution context's PrivateEnvironment to classPrivateEnvironment.
  14. If constructor is empty, then
    1. Let defaultConstructor be a new Abstract Closure with no parameters that captures nothing and performs the following steps when called:
      1. Let args be the List of arguments that was passed to this function by [[Call]] or [[Construct]].
      2. If NewTarget is undefined, throw a TypeError exception.
      3. Let F be the active function object.
      4. If F.[[ConstructorKind]] is derived, then
        1. NOTE: This branch behaves similarly to constructor(...args) { super(...args); }. The most notable distinction is that while the aforementioned ECMAScript source text observably calls the @@iterator method on %Array.prototype%, this function does not.
        2. Let func be ! F.[[GetPrototypeOf]]().
        3. If IsConstructor(func) is false, throw a TypeError exception.
        4. Let result be ? Construct(func, args, NewTarget).
      5. Else,
        1. NOTE: This branch behaves similarly to constructor() {}.
        2. Let result be ? OrdinaryCreateFromConstructor(NewTarget, "%Object.prototype%").
      6. Perform ? InitializeInstanceElements(result, F).
      7. Return result.
    2. Let F be CreateBuiltinFunction(defaultConstructor, 0, className, « [[ConstructorKind]], [[SourceText]] », the current Realm Record, constructorParent).
  15. Else,
    1. Let constructorInfo be ! DefineMethod of constructor with arguments proto and constructorParent.
    2. Let F be constructorInfo.[[Closure]].
    3. Perform MakeClassConstructor(F).
    4. Perform SetFunctionName(F, className).
  16. Perform MakeConstructor(F, false, proto).
  17. If ClassHeritage is present, set F.[[ConstructorKind]] to derived.
  18. Perform CreateMethodProperty(proto, "constructor", F).
  19. If ClassBody is not present, let elements be a new empty List.
  20. Else, let elements be NonConstructorElements of ClassBody.
  21. Let instancePrivateMethods be a new empty List.
  22. Let staticPrivateMethods be a new empty List.
  23. Let instanceFields be a new empty List.
  24. Let staticElements be a new empty List.
  25. For each ClassElement e of elements, do
    1. If IsStatic of e is false, then
      1. Let element be Completion(ClassElementEvaluation of e with argument proto).
    2. Else,
      1. Let element be Completion(ClassElementEvaluation of e with argument F).
    3. If element is an abrupt completion, then
      1. Set the running execution context's LexicalEnvironment to env.
      2. Set the running execution context's PrivateEnvironment to outerPrivateEnvironment.
      3. Return ? element.
    4. Set element to ! element.
    5. If element is a PrivateElement, then
      1. Assert: element.[[Kind]] is either method or accessor.
      2. If IsStatic of e is false, let container be instancePrivateMethods.
      3. Else, let container be staticPrivateMethods.
      4. If container contains a PrivateElement pe such that pe.[[Key]] is element.[[Key]], then
        1. Assert: element.[[Kind]] and pe.[[Kind]] are both accessor.
        2. If element.[[Get]] is undefined, then
          1. Let combined be PrivateElement { [[Key]]: element.[[Key]], [[Kind]]: accessor, [[Get]]: pe.[[Get]], [[Set]]: element.[[Set]] }.
        3. Else,
          1. Let combined be PrivateElement { [[Key]]: element.[[Key]], [[Kind]]: accessor, [[Get]]: element.[[Get]], [[Set]]: pe.[[Set]] }.
        4. Replace pe in container with combined.
      5. Else,
        1. Append element to container.
    6. Else if element is a ClassFieldDefinition Record, then
      1. If IsStatic of e is false, append element to instanceFields.
      2. Else, append element to staticElements.
    7. Else if element is a ClassStaticBlockDefinition Record, then
      1. Append element to staticElements.
  26. Set the running execution context's LexicalEnvironment to env.
  27. If classBinding is not undefined, then
    1. Perform ! classEnv.InitializeBinding(classBinding, F).
  28. Set F.[[PrivateMethods]] to instancePrivateMethods.
  29. Set F.[[Fields]] to instanceFields.
  30. For each PrivateElement method of staticPrivateMethods, do
    1. Perform ! PrivateMethodOrAccessorAdd(F, method).
  31. For each element elementRecord of staticElements, do
    1. If elementRecord is a ClassFieldDefinition Record, then
      1. Let result be Completion(DefineField(F, elementRecord)).
    2. Else,
      1. Assert: elementRecord is a ClassStaticBlockDefinition Record.
      2. Let result be Completion(Call(elementRecord.[[BodyFunction]], F)).
    3. If result is an abrupt completion, then
      1. Set the running execution context's PrivateEnvironment to outerPrivateEnvironment.
      2. Return ? result.
  32. Set the running execution context's PrivateEnvironment to outerPrivateEnvironment.
  33. Return F.

15.7.15 Runtime Semantics: BindingClassDeclarationEvaluation

The syntax-directed operation BindingClassDeclarationEvaluation takes no arguments and returns either a normal completion containing a function object or an abrupt completion. It is defined piecewise over the following productions:

ClassDeclaration : class BindingIdentifier ClassTail
  1. Let className be StringValue of BindingIdentifier.
  2. Let value be ? ClassDefinitionEvaluation of ClassTail with arguments className and className.
  3. Set value.[[SourceText]] to the source text matched by ClassDeclaration.
  4. Let env be the running execution context's LexicalEnvironment.
  5. Perform ? InitializeBoundName(className, value, env).
  6. Return value.
ClassDeclaration : class ClassTail
  1. Let value be ? ClassDefinitionEvaluation of ClassTail with arguments undefined and "default".
  2. Set value.[[SourceText]] to the source text matched by ClassDeclaration.
  3. Return value.
Note

ClassDeclaration : class ClassTail only occurs as part of an ExportDeclaration and establishing its binding is handled as part of the evaluation action for that production. See 16.2.3.7.

15.7.16 Runtime Semantics: Evaluation

ClassDeclaration : class BindingIdentifier ClassTail
  1. Perform ? BindingClassDeclarationEvaluation of this ClassDeclaration.
  2. Return empty.
Note

ClassDeclaration : class ClassTail only occurs as part of an ExportDeclaration and is never directly evaluated.

ClassExpression : class ClassTail
  1. Let value be ? ClassDefinitionEvaluation of ClassTail with arguments undefined and "".
  2. Set value.[[SourceText]] to the source text matched by ClassExpression.
  3. Return value.
ClassExpression : class BindingIdentifier ClassTail
  1. Let className be StringValue of BindingIdentifier.
  2. Let value be ? ClassDefinitionEvaluation of ClassTail with arguments className and className.
  3. Set value.[[SourceText]] to the source text matched by ClassExpression.
  4. Return value.
ClassElementName : PrivateIdentifier
  1. Let privateIdentifier be StringValue of PrivateIdentifier.
  2. Let privateEnvRec be the running execution context's PrivateEnvironment.
  3. Let names be privateEnvRec.[[Names]].
  4. Assert: Exactly one element of names is a Private Name whose [[Description]] is privateIdentifier.
  5. Let privateName be the Private Name in names whose [[Description]] is privateIdentifier.
  6. Return privateName.
ClassStaticBlockStatementList : [empty]
  1. Return undefined.