ECMAScript Classes 1.1

Introduction

See the proposal repository for motivation, basic concepts, and code examples.

1Syntax

ClassElement[Yield, Await]:InstanceVariableDeclaration[?Yield, ?Await] MethodDefinition[?Yield, ?Await] HiddenMethod[?Yield, ?Await] staticMethodDefinition[?Yield, ?Await] staticHiddenMethod[?Yield, ?Await] ClassInitializer ; HiddenMethod[Yield, Await]:hiddenMethodDefinition[?Yield, ?Await] InstanceVariableDeclaration[Yield, Await]:varInstanceVariableList[?Yield, ?Await]; InstanceVariableList[Yield, Await]:BindingIdentifier[?Yield, ?Await] InstanceVariableList,BindingIdentifier[?Yield, ?Await] ClassInitializer:static{FunctionBody[~Yield, ~Await]} MemberExpression[Yield, Await]:PrimaryExpression[?Yield, ?Await] MemberExpression[?Yield, ?Await][Expression[+In, ?Yield, ?Await]] MemberExpression[?Yield, ?Await].IdentifierName MemberExpression[?Yield, ?Await]->IdentifierName MemberExpression[?Yield, ?Await]TemplateLiteral[?Yield, ?Await] SuperProperty[?Yield, ?Await] MetaProperty newMemberExpression[?Yield, ?Await]Arguments[?Yield, ?Await] CallExpression[Yield, Await]:CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await] SuperCall[?Yield, ?Await] CallExpression[?Yield, ?Await]Arguments[?Yield, ?Await] CallExpression[?Yield, ?Await][Expression[+In, ?Yield, ?Await]] CallExpression[?Yield, ?Await].IdentifierName CallExpression[?Yield, ?Await]->IdentifierName CallExpression[?Yield, ?Await]TemplateLiteral[?Yield, ?Await]

2Static Semantics

2.1Early Errors

ScriptBody:StatementList ModuleBody:ModuleItemList HiddenMethod:hiddenMethodDefinition ClassBody:ClassElementList ClassElement:ClassInitializer
  1. It is a Syntax Error if HasDirectSuper of ClassInitializer is true.
UnaryExpression:deleteUnaryExpression Note

The last rule means that expressions such as delete (((foo))) produce early errors because of recursive application of the first rule.

2.2PropName

Editor's Note

PropName returns empty for hidden method definitions and non-method class elements.

HiddenMethod:hiddenMethodDefintion
  1. Return empty.
ClassElement:; ClassElement:InstanceVariableDeclaration ClassElement:ClassInitializer
  1. Return empty.

2.3Contains

With parameter symbol.

HiddenMethod:hiddenMethodDefinition
  1. If symbol is MethodDefinition, return true.
  2. Return false.
Note

Static semantic rules that depend upon substructure generally do not look into function definitions.

2.4MethodHasIdentifierName

Editor's Note

MethodHasIdentifierName of a MethodDefinition returns true if it derives a method with an IdentifierName property name.

MethodDefinition:PropertyName(UniqueFormalParameters){FunctionBody} MethodDefinition:getPropertyName(){FunctionBody} MethodDefinition:setPropertyName(PropertySetParameterList){FunctionBody} GeneratorMethod:*PropertyName(UniqueFormalParameters){GeneratorBody} AsyncMethod:async[no LineTerminator here]PropertyName(UniqueFormalParameters){AsyncFunctionBody} AsyncGeneratorMethod:async[no LineTerminator here]*PropertyName(UniqueFormalParameters){AsyncGeneratorBody}
  1. Return MethodHasIdentifierName of PropertyName.
LiteralPropertyName:StringLiteral LiteralPropertyName:NumericLiteral ComputedPropertyName:[AssignmentExpression]
  1. Return false.
LiteralPropertyName:IdentifierName
  1. Return true.

2.5HiddenNames

Editor's Note
HiddenNames of a ClassElementList returns a List containing all of the hidden member names defined in the class body. Each element in the list is a Record of the form {[[Name]]: string, [[Kind]]: string}.
MethodDefinition:PropertyName(UniqueFormalParameters){FunctionBody} GeneratorMethod:*PropertyName(UniqueFormalParameters){GeneratorBody} AsyncMethod:async[no LineTerminator here]PropertyName(UniqueFormalParameters){AsyncFunctionBody} AsyncGeneratorMethod:async[no LineTerminator here]*PropertyName(UniqueFormalParameters){AsyncGeneratorBody}
  1. Let name be PropName of PropertyName.
  2. If name is empty, return a new empty List.
  3. Return a new List containing the Record{ [[Name]]: name, [[Kind]]: "method" }.
MethodDefinition:getPropertyName(){FunctionBody}
  1. Let name be PropName of PropertyName.
  2. If name is empty, return a new empty List.
  3. Return a new List containing the Record{ [[Name]]: name, [[Kind]]: "get" }.
MethodDefinition:setPropertyName(PropertySetParameterList){FunctionBody}
  1. Let name be PropName of PropertyName.
  2. If name is empty, return a new empty List.
  3. Return a new List containing the Record{ [[Name]]: name, [[Kind]]: "set" }.
ClassElementList:ClassElementListClassElement
  1. Let hiddenNames be HiddenNames of ClassElementList.
  2. Let newNames be HiddenNames of ClassElement.
  3. Append the elements of newNames to hiddenNames.
  4. Return hiddenNames.
ClassElement:MethodDefinition ClassElement:staticMethodDefinition ClassElement:; ClassElement:ClassInitializer
  1. Return a new empty List.
InstanceVariableList:BindingIdentifier
  1. Let name be StringValue of BindingIdentifier.
  2. Return a new List containing the Record{ [[Name]]: name, [[Kind]]: "var" }.
InstanceVariableList:InstanceVariableList,BindingIdentifier
  1. Let hiddenNames be HiddenNames of InstanceVariableList.
  2. Let name be StringValue of BindingIdentifier.
  3. Let record be a new Record{ [[Name]]: name, [[Kind]]: "var" }.
  4. Append record to hiddenNames.
  5. Return hiddenNames.

2.6HasDuplicateHiddenNames ( parseNode )

Editor's Note
HasDuplicateHiddenNames returns true if a class body contains more than one definition for a single hidden name, and those definitions do not form an accessor method pair.
  1. Assert: parseNode is ClassElementList.
  2. Let members be HiddenNames of parseNode.
  3. For each element member of members, do
    1. For each element otherMember of members, do
      1. If otherMember is not member and otherMember.[[Name]] is member.[[Name]], then
        1. If otherMember.[[Kind]] is "set", then
          1. If member.[[Kind]] is not "get", return true.
        2. Else if otherMember.[[Kind]] is "get", then
          1. If member.[[Kind]] is not "set", return true.
        3. Else, return true.
  4. Return false.

2.7ContainsInvalidHiddenReferences

Editor's Note
ContainsInvalidHiddenReferences of a parse node returns true if it contains any hidden references that are statically unresolvable or invalid using the initial set of member definitions in the parameter hiddenNames. ContainsInvalidHiddenReferences is a recursively applied semantic rule.

With parameter hiddenNames.

TODO

2.8ClassInitializerElement

Editor's Note
ClassInitializerElement of ClassElementList returns the first ClassInitializer within a class definition. Early errors prevent multiple occurrances of ClassInitializer within a single class definition.
ClassElementList:ClassElement
  1. If ClassElement is ClassElement:ClassInitializer , return ClassElement.
  2. Return empty.
ClassElementList:ClassElementListClassElement
  1. Let head be ClassInitializerElement of ClassElementList.
  2. If head is not empty, return head.
  3. Return ClassInitializerElement of ClassElement.

2.9HasMultipleClassInitializers

Editor's Note
HasMultipleClassInitializers of ClassElementList returns true if the containing class body contains more than one occurance of ClassInitializer.
ClassElementList:ClassElement
  1. Return false.
ClassElementList:ClassElementListClassElement
  1. If ClassElementList Contains ClassInitializer and ClassElement Contains ClassInitializer, return true.
  2. Return false.

2.10IsStatic

ClassElement:MethodDefinition ClassElement:HiddenMethod ClassElement:InstanceVariableDeclaration ClassElement:;
  1. Return false.
ClassElement:staticMethodDefinition ClassElement:staticHiddenMethod ClassElement:ClassInitializer
  1. Return true.

2.11IsHiddenClassElement

Editor's Note
IsHiddenClassElement of ClassElement returns true if the class element is a hidden method or instance variable declaration.
ClassElement:InstanceVariableDeclaration ClassElement:HiddenMethod ClassElement:staticHiddenMethod ClassElement:ClassInitializer
  1. Return true.
ClassElement:; ClassElement:MethodDefinition ClassElement:staticMethodDefinition
  1. Return false.

2.12NonConstructorClassElements

Editor's Note
NonConstructorClassElements of ClassElementList returns all non-empty ClassElement parse nodes other than the class constructor method.
ClassElementList:ClassElement
  1. If ClassElement is ClassElement:; , return a new empty List.
  2. If IsStatic of ClassElement is false and PropName of ClassElement is "constructor", return a new empty List.
  3. Return a List containing ClassElement.
ClassElementList:ClassElementListClassElement
  1. Let list be NonConstructorClassElements of ClassElementList.
  2. If ClassElement is ClassElement:; , return list.
  3. If IsStatic of ClassElement is false and PropName of ClassElement is "constructor", return list.
  4. Append ClassElement to the end of list.
  5. Return list.

3Runtime Semantics

3.1Evaluation

SuperCall:superArguments
  1. Let newTarget be GetNewTarget().
  2. Assert: Type(newTarget) is Object.
  3. Let func be ? GetSuperConstructor().
  4. Let argList be ArgumentListEvaluation of Arguments.
  5. ReturnIfAbrupt(argList).
  6. Let result be ? Construct(func, argList, newTarget).
  7. Let thisER be GetThisEnvironment().
  8. Perform ? thisER.BindThisValue(result).
  9. Perform ? InitializeInstanceVariables(result, thisER.[[FunctionObject]]).
  10. Return result.
MemberExpression:MemberExpression->IdentifierName
  1. Let baseReference be the result of evaluating MemberExpression.
  2. Let baseValue be ? GetValue(baseReference).
  3. Let bv be ? RequireObjectCoercible(baseValue).
  4. Let env be the running execution context's LexicalEnvironment.
  5. Let hmd be ? GetHiddenBindingValue(StringValue of IdentifierName, env).
  6. Assert: hmd is a HiddenMemberDescriptor Record.
  7. If the code matched by this MemberExpression is strict mode code, let strict be true, else let strict be false.
  8. Return a value of type Reference whose base value component is bv, whose referenced name component is hmd, and whose strict reference flag is strict.
CallExpression:CallExpression->IdentifierName

Is evaluated in exactly the same manner as MemberExpression:MemberExpression->IdentifierName except that the contained CallExpression is evaluated in step 1.

Note
Early error rules ensure that hidden names are always resolvable to hidden member descriptors.

3.2ObjectCreate ( proto [ , internalSlotsList ] )

The abstract operation ObjectCreate with argument proto (an object or null) is used to specify the runtime creation of new ordinary objects. The optional argument internalSlotsList is a List of the names of additional internal slots that must be defined as part of the object. If the list is not provided, a new empty List is used. This abstract operation performs the following steps:

  1. If internalSlotsList is not present, set internalSlotsList to a new empty List.
  2. Let obj be a newly created object with an internal slot for each name in internalSlotsList.
  3. Set obj's essential internal methods to the default ordinary object definitions specified in 9.1.
  4. Set obj.[[Prototype]] to proto.
  5. Set obj.[[Extensible]] to true.
  6. Set obj.[[InstanceVariables]] to an empty List.
  7. Return obj.

3.3[[Construct]] ( argumentsList, newTarget )

The [[Construct]] internal method for an ECMAScript function object F is called with parameters argumentsList and newTarget. argumentsList is a possibly empty List of ECMAScript language values. The following steps are taken:

  1. Assert: F is an ECMAScript function object.
  2. Assert: Type(newTarget) is Object.
  3. Let callerContext be the running execution context.
  4. Let kind be F.[[ConstructorKind]].
  5. If kind is "base", then
    1. Let thisArgument be ? OrdinaryCreateFromConstructor(newTarget, "%ObjectPrototype%").
  6. Let calleeContext be PrepareForOrdinaryCall(F, newTarget).
  7. Assert: calleeContext is now the running execution context.
  8. If kind is "base", then
    1. Perform OrdinaryCallBindThis(F, calleeContext, thisArgument).
    2. Perform ! InitializeInstanceVariables(thisArgument, F).
  9. Let constructorEnv be the LexicalEnvironment of calleeContext.
  10. Let envRec be constructorEnv's EnvironmentRecord.
  11. Let result be OrdinaryCallEvaluateBody(F, argumentsList).
  12. Remove calleeContext from the execution context stack and restore callerContext as the running execution context.
  13. If result.[[Type]] is return, then
    1. If Type(result.[[Value]]) is Object, return NormalCompletion(result.[[Value]]).
    2. If kind is "base", return NormalCompletion(thisArgument).
    3. If result.[[Value]] is not undefined, throw a TypeError exception.
  14. Else, ReturnIfAbrupt(result).
  15. Return ? envRec.GetThisBinding().

3.4DefineMethod

Editor's Note
DefineMethod has been generalized to create methods for all method definition productions.

With parameter homeObject.

MethodDefinition:PropertyName(UniqueFormalParameters){FunctionBody}
  1. Let propKey be the result of evaluating PropertyName.
  2. ReturnIfAbrupt(propKey).
  3. If the function code for this MethodDefinition is strict mode code, let strict be true. Otherwise let strict be false.
  4. Let scope be the running execution context's LexicalEnvironment.
  5. Let closure be FunctionCreate(Method, UniqueFormalParameters, FunctionBody, scope, strict).
  6. Perform MakeMethod(closure, homeObject).
  7. Perform ! SetFunctionName(closure, propKey).
  8. Return the Record{ [[Key]]: propKey, [[Closure]]: closure }.
MethodDefinition:getPropertyName(){FunctionBody}
  1. Let propKey be the result of evaluating PropertyName.
  2. ReturnIfAbrupt(propKey).
  3. If the function code for this MethodDefinition is strict mode code, let strict be true. Otherwise let strict be false.
  4. Let scope be the running execution context's LexicalEnvironment.
  5. Let formalParameterList be an instance of the production FormalParameters:[empty] .
  6. Let closure be FunctionCreate(Method, formalParameterList, FunctionBody, scope, strict).
  7. Perform MakeMethod(closure, homeObject).
  8. Perform ! SetFunctionName(closure, propKey, "get").
  9. Return the Record{ [[Key]]: propKey, [[Closure]]: closure }.
MethodDefinition:setPropertyName(PropertySetParameterList){FunctionBody}
  1. Let propKey be the result of evaluating PropertyName.
  2. ReturnIfAbrupt(propKey).
  3. If the function code for this MethodDefinition is strict mode code, let strict be true. Otherwise let strict be false.
  4. Let scope be the running execution context's LexicalEnvironment.
  5. Let closure be FunctionCreate(Method, PropertySetParameterList, FunctionBody, scope, strict).
  6. Perform MakeMethod(closure, homeObject).
  7. Perform ! SetFunctionName(closure, propKey, "set").
  8. Return the Record{ [[Key]]: propKey, [[Closure]]: closure }.
GeneratorMethod:*PropertyName(UniqueFormalParameters){GeneratorBody}
  1. Let propKey be the result of evaluating PropertyName.
  2. ReturnIfAbrupt(propKey).
  3. If the function code for this GeneratorMethod is strict mode code, let strict be true. Otherwise let strict be false.
  4. Let scope be the running execution context's LexicalEnvironment.
  5. Let closure be GeneratorFunctionCreate(Method, UniqueFormalParameters, GeneratorBody, scope, strict).
  6. Perform MakeMethod(closure, homeObject).
  7. Let prototype be ObjectCreate(%GeneratorPrototype%).
  8. Perform DefinePropertyOrThrow(closure, "prototype", PropertyDescriptor{[[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false}).
  9. Perform ! SetFunctionName(closure, propKey).
  10. Return the Record{ [[Key]]: propKey, [[Closure]]: closure }.
AsyncMethod:async[no LineTerminator here]PropertyName(UniqueFormalParameters){AsyncFunctionBody}
  1. Let propKey be the result of evaluating PropertyName.
  2. ReturnIfAbrupt(propKey).
  3. If the function code for this AsyncMethod is strict mode code, let strict be true. Otherwise let strict be false.
  4. Let scope be the LexicalEnvironment of the running execution context.
  5. Let closure be ! AsyncFunctionCreate(Method, UniqueFormalParameters, AsyncFunctionBody, scope, strict).
  6. Perform ! MakeMethod(closure, homeObject).
  7. Perform ! SetFunctionName(closure, propKey).
  8. Return the Record{ [[Key]]: propKey, [[Closure]]: closure }.
AsyncGeneratorMethod:async[no LineTerminator here]*PropertyName(UniqueFormalParameters){AsyncGeneratorBody}
  1. Let propKey be the result of evaluating PropertyName.
  2. ReturnIfAbrupt(propKey).
  3. If the function code for this AsyncGeneratorMethod is strict mode code, let strict be true. Otherwise let strict be false.
  4. Let scope be the running execution context's LexicalEnvironment.
  5. Let closure be ! AsyncGeneratorFunctionCreate(Method, UniqueFormalParameters, AsyncGeneratorBody, scope, strict).
  6. Perform ! MakeMethod(closure, homeObject).
  7. Let prototype be ! ObjectCreate(%AsyncGeneratorPrototype%).
  8. Perform ! DefinePropertyOrThrow(closure, "prototype", PropertyDescriptor{[[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false}).
  9. Perform ! SetFunctionName(closure, propKey).
  10. Return the Record{ [[Key]]: propKey, [[Closure]]: closure }.
ClassInitializer:static{FunctionBody}
  1. Let scope be the running execution context's LexicalEnvironment.
  2. Let formalParameterList be an instance of the production FormalParameters:[empty] .
  3. Let closure be FunctionCreate(Method, formalParameterList, FunctionBody, scope, true).
  4. Perform MakeMethod(closure, homeObject).
  5. Return the Record { [[Key]]: empty, [[Closure]]: closure }.

3.5PropertyDefinitionEvaluation

Editor's Note
PropertyDefinitionEvaluation of MethodDefinition productions has been refactored to use DefineMethod.
Editor's Note
PropertyDefinitionEvaluation does not process hidden definitions. Hidden method definitions are evaluated separately in HiddenDefinitionEvaluation.

With parameters object and enumerable.

MethodDefinition:PropertyName(UniqueFormalParameters){FunctionBody}
  1. Let methodDef be DefineMethod of MethodDefinition with argument object.
  2. ReturnIfAbrupt(methodDef).
  3. Let desc be the PropertyDescriptor{ [[Value]]: methodDef.[[Closure]], [[Writable]]: true, [[Enumerable]]: enumerable, [[Configurable]]: true }.
  4. Return ? DefinePropertyOrThrow(object, methodDef.[[Key]], desc).
MethodDefinition:getPropertyName(){FunctionBody}
  1. Let methodDef be DefineMethod of MethodDefinition with argument object.
  2. ReturnIfAbrupt(methodDef).
  3. Let desc be the PropertyDescriptor{ [[Get]]: methodDef.[[Closure]], [[Enumerable]]: enumerable, [[Configurable]]: true }.
  4. Return ? DefinePropertyOrThrow(object, methodDef.[[Key]], desc).
MethodDefinition:setPropertyName(PropertySetParameterList){FunctionBody}
  1. Let methodDef be DefineMethod of MethodDefinition with argument object.
  2. ReturnIfAbrupt(methodDef).
  3. Let desc be the PropertyDescriptor{ [[Set]]: methodDef.[[Closure]], [[Enumerable]]: enumerable, [[Configurable]]: true }.
  4. Return ? DefinePropertyOrThrow(object, methodDef.[[Key]], desc).
GeneratorMethod:*PropertyName(UniqueFormalParameters){GeneratorBody}
  1. Let methodDef be DefineMethod of GeneratorMethod with argument object.
  2. ReturnIfAbrupt(methodDef).
  3. Let desc be the PropertyDescriptor{ [[Value]]: methodDef.[[Closure]], [[Writable]]: true, [[Enumerable]]: enumerable, [[Configurable]]: true }.
  4. Return ? DefinePropertyOrThrow(object, methodDef.[[Key]], desc).
AsyncMethod:async[no LineTerminator here]PropertyName(UniqueFormalParameters){AsyncFunctionBody}
  1. Let methodDef be DefineMethod of AsyncMethod with argument object.
  2. ReturnIfAbrupt(methodDef).
  3. Let desc be the PropertyDescriptor{ [[Value]]: methodDef.[[Closure]], [[Writable]]: true, [[Enumerable]]: enumerable, [[Configurable]]: true }.
  4. Return ? DefinePropertyOrThrow(object, methodDef.[[Key]], desc).
AsyncGeneratorMethod:async[no LineTerminator here]*PropertyName(UniqueFormalParameters){AsyncGeneratorBody}
  1. Let methodDef be DefineMethod of AsyncGeneratorMethod with argument object.
  2. ReturnIfAbrupt(methodDef).
  3. Let desc be the PropertyDescriptor{ [[Value]]: methodDef.[[Closure]], [[Writable]]: true, [[Enumerable]]: enumerable, [[Configurable]]: true }.
  4. Return ? DefinePropertyOrThrow(object, methodDef.[[Key]], desc).
HiddenMethod:hiddenMethodDefinition
  1. Return.
ClassElement:InstanceVariableDeclaration ClassElement:ClassInitializer
  1. Return.

3.6HiddenDefinitionEvaluation

Editor's Note
HiddenDefinitionEvaluation evaluates hidden class elements and populates the specified hiddenDefinitions List with HiddenMemberDescriptors.

With parameters object and hiddenDefinitions.

MethodDefinition:PropertyName(UniqueFormalParameters){FunctionBody} MethodDefinition:GeneratorMethod MethodDefinition:AsyncMethod MethodDefinition:AsyncGeneratorMethod
  1. Let methodDef be DefineMethod of MethodDefinition with argument object.
  2. Assert: methodDef is not an abrupt completion.
  3. Let hmd be the HiddenMemberDescriptor{ [[Name]]: methodDef.[[Key]], [[Value]]: methodDef.[[Closure]] }.
  4. Append hmd to hiddenDefinitions.
MethodDefinition:getPropertyName(){FunctionBody}
  1. Let methodDef be DefineMethod of MethodDefinition with argument object.
  2. ReturnIfAbrupt(methodDef).
  3. For each element hmd of hiddenDefinitions,
    1. If hmd.[[Name]] is methodDef.[[Name]],
      1. Assert: hmd.[[Get]] is undefined.
      2. Set hmd.[[Get]] to methodDef.[[Closure]].
      3. Return.
  4. Let hmd be the HiddenMemberDescriptor{ [[Name]]: methodDef.[[Key]], [[Get]]: methodDef.[[Closure]], [[Set]]: undefined }.
  5. Append hmd to hiddenDefinitions.
MethodDefinition:setPropertyName(PropertySetParameterList){FunctionBody}
  1. Let methodDef be DefineMethod of MethodDefinition with argument object.
  2. ReturnIfAbrupt(methodDef).
  3. For each element hmd of hiddenDefinitions,
    1. If hmd.[[Name]] is methodDef.[[Name]],
      1. Assert: hmd.[[Set]] is undefined.
      2. Set hmd.[[Set]] to methodDef.[[Closure]].
      3. Return.
  4. Let hmd be the HiddenMemberDescriptor{ [[Name]]: methodDef.[[Key]], [[Get]]: undefined, [[Set]]: methodDef.[[Closure]] }.
  5. Append hmd to hiddenDefinitions.
InstanceVariableList:BindingIdentifier
  1. Let name be StringValue of BindingIdentifier.
  2. Let key be a new unique instance variable key.
  3. Let hmd be the HiddenMemberDescriptor{ [[Name]]: name, [[InstanceVariableKey]]: key }.
  4. Append hmd to hiddenDefinitions.
InstanceVariableList:InstanceVariableList,BindingIdentifier
  1. Perform ! HiddenDefinitionEvaluation of InstanceVariableList with arguments object and hiddenDefinitions.
  2. Let key be a new unique instance variable key.
  3. Let name be StringValue of BindingIdentifier.
  4. Let hmd be the HiddenMemberDescriptor{ [[Name]]: name, [[InstanceVariableKey]]: key }.
  5. Append hmd to hiddenDefinitions.
ClassElement:ClassInitializer
  1. Return.

3.7ClassDefinitionEvaluation

With parameter className.

ClassTail:ClassHeritageopt{ClassBodyopt}
  1. Let lex be the LexicalEnvironment of the running execution context.
  2. Let classScope be NewDeclarativeEnvironment(lex).
  3. Let classScopeEnvRec be classScope's EnvironmentRecord.
  4. If className is not undefined, then
    1. Perform classScopeEnvRec.CreateImmutableBinding(className, true).
  5. If ClassHeritageopt is not present, then
    1. Let protoParent be the intrinsic object %ObjectPrototype%.
    2. Let constructorParent be the intrinsic object %FunctionPrototype%.
  6. Else,
    1. Set the running execution context's LexicalEnvironment to classScope.
    2. Let superclass be the result of evaluating ClassHeritage.
    3. Set the running execution context's LexicalEnvironment to lex.
    4. ReturnIfAbrupt(superclass).
    5. If superclass is null, then
      1. Let protoParent be null.
      2. Let constructorParent be the intrinsic object %FunctionPrototype%.
    6. Else if IsConstructor(superclass) is false, throw a TypeError exception.
    7. Else,
      1. Let protoParent be ? Get(superclass, "prototype").
      2. If Type(protoParent) is neither Object nor Null, throw a TypeError exception.
      3. Let constructorParent be superclass.
  7. Let proto be ObjectCreate(protoParent).
  8. If ClassBodyopt is not present, let constructor be empty.
  9. Else, let constructor be ConstructorMethod of ClassBody.
  10. If constructor is empty, then
    1. If ClassHeritageopt is present, then
      1. Set constructor to the result of parsing the source text
        constructor(... args){ super (...args);}
        using the syntactic grammar with the goal symbol MethodDefinition[~Yield, ~Await].
    2. Else,
      1. Set constructor to the result of parsing the source text
        constructor( ){ }
        using the syntactic grammar with the goal symbol MethodDefinition[~Yield, ~Await].
  11. If ClassBodyopt is not present, let classElements be a new empty List.
  12. Else, let classElements be NonConstructorClassElements of ClassBody.
  13. Let hiddenScope be NewDeclarativeEnvironment(classScope).
  14. Let hiddenDefinitions be a new empty List.
  15. For each element element of classElements, do
    1. If IsHiddenClassElement of element is true, then
      1. If IsStatic of element is true, let homeObject be F.
      2. Else, let homeObject be proto.
      3. Perform ! HiddenDefinitionEvaluation of ClassElement with arguments hiddenDefinitions and homeObject.
  16. Perform ! CreateHiddenBindings(hiddenDefinitions, hiddenScope).
  17. Set the running execution context's LexicalEnvironment to hiddenScope.
  18. Let F be the result of performing DefineClassConstructorMethod for constructor with arguments proto and constructorParent.
  19. If ClassHeritageopt is present, set F.[[ConstructorKind]] to "derived".
  20. Perform MakeConstructor(F, false, proto).
  21. Perform MakeClassConstructor(F).
  22. Perform CreateMethodProperty(proto, "constructor", F).
  23. For each element element in order from classElements, do
    1. If IsStatic of element is true, then let homeObject be F.
    2. Else, let homeObject be proto.
    3. Let status be the result of performing PropertyDefinitionEvaluation for element with arguments homeObject and false.
    4. If status is an abrupt completion, then
      1. Set the running execution context's LexicalEnvironment to lex.
      2. Return Completion(status).
  24. If className is not undefined, then
    1. Perform classScopeEnvRec.InitializeBinding(className, F).
  25. Let instanceVariableKeys be a new empty List.
  26. For each element hmd of hiddenDefinitions, do
    1. If GetHiddenMemberDescriptorKind(hmd) is "var", then
      1. Append hiddenDef.[[InstanceVariableKey]] to instanceVariableKeys.
  27. Set F.[[InstanceVariableKeys]] to instanceVariableKeys.
  28. Perform ! InitializeHiddenBindings(hiddenDefinitions, hiddenScope).
  29. If ClassBodyopt is present, let initializer be ClassInitializerElement of ClassBody.
  30. Else, let initializer be empty.
  31. If initializer is not empty, then
    1. Let initializerInfo be DefineMethod of initializer with argument F.
    2. Let status be Call(initializerInfo.[[Closure]], F, « »).
    3. If status is an abrupt completion, then
      1. Set the running execution context's LexicalEnvironment to lex.
      2. Return Completion(status).
  32. Set the running execution context's LexicalEnvironment to lex.
  33. Return F.

3.8DefineClassConstructorMethod

With parameters homeObject and functionPrototype.

MethodDefinition:PropertyName(UniqueFormalParameters){FunctionBody}
  1. Let strict be true.
  2. Let scope be the running execution context's LexicalEnvironment.
  3. Let closure be FunctionCreate(Normal, UniqueFormalParameters, FunctionBody, scope, strict, functionPrototype).
  4. Perform MakeMethod(closure, object).
  5. Return closure.

3.9InitializeInstanceVariables ( obj, constructor )

  1. Assert: Type(obj) is Object.
  2. Assert: constructor is an ECMAScript function object.
  3. Let keys be constructor.[[InstanceVariableKeys]].
  4. If keys is undefined or an empty List, return.
  5. Let instanceVars be obj.[[InstanceVariables]].
  6. For each element key of keys, do
    1. For each element var of instanceVars, do
      1. If var.[[Key]] is key, throw a TypeError exception.
    2. Let var be a new Record{ [[Key]]: key, [[Value]]: undefined }.
    3. Append var to instanceVars.

3.10EvalDeclarationInstantiation( body, varEnv, lexEnv, strict )

TODO

4Hidden Member Descriptors

The Hidden Member Descriptor type is used to explain the behavior of hidden member references. The schema name used within this specification to tag literal descriptions of Hidden Member Descriptor records is "HiddenMemberDescriptor".

Values of the Hidden Member Descriptor type are Records that contain at least a [[Name]] field. Hidden Member Descriptors may be classified as instance variable descriptors, method descriptors, or accessor descriptors.

An instance variable Hidden Member Descriptor is a Record with the following fields.

Table 1: Instance Variable Hidden Member Descriptor Fields
Field Name Value Meaning
[[Name]] string The name of the instance variable.
[[InstanceVariableKey]] A unique instance variable key A unique key identifying the instance variable.

A method Hidden Member Descriptor is a Record with the following fields.

Table 2: Method Hidden Member Descriptor Fields
Field Name Value Meaning
[[Name]] string The name of the hidden method.
[[Value]] Object A function object corresponding to a hidden method definition.

An accessor Hidden Member Descriptor is a Record with the following fields.

Table 3: Accesor Hidden Member Descriptor Fields
Field Name Value Meaning
[[Name]] string The name of the hidden accessor.
[[Get]] Object | undefined If the value is an Object it must be a function object. The function's [[Call]] internal method is called with an empty arguments list to retrieve a hidden property value each time a get access of a hidden reference is performed.
[[Set]] Object | undefined If the value is an Object it must be a function object. The function's [[Call]] internal method is called with an arguments list containing the assigned value as its sole argument each time a set access of a hidden reference is performed.

The following abstract operations are used in this specification to operate upon Hidden Member Descriptor values:

4.1GetHiddenMemberDescriptorKind ( desc )

  1. Assert: Type(desc) is HiddenMemberDescriptor.
  2. If desc has an [[InstanceVariableKey]] field, return "var".
  3. If desc has a [[Get]] or [[Set]] field, return "accessor".
  4. Else, return "method".

4.2CreateHiddenBindings ( hiddenDefinitions, env )

  1. Assert: hiddenDefinitions is a List.
  2. Assert: env is a Lexical Environment.
  3. Let envRec be env's EnvironmentRecord.
  4. For each element hmd of hiddenDefinitions, do
    1. Let boundName be the string-concatenation of "->" and hmd.[[Name]].
    2. Perform ! envRec.CreateImmutableBinding(boundName, true).

4.3InitializeHiddenBindings ( hiddenDefinitions, env )

  1. Assert: hiddenDefinitions is a List.
  2. Assert: env is a Lexical Environment.
  3. Let envRec be env's EnvironmentRecord.
  4. For each element hmd of hiddenDefinitions, do
    1. Let boundName be the string-concatenation of "->" and hmd.[[Name]].
    2. Perform ! envRec.InitializeBinding(boundName, hmd).

4.4GetHiddenBindingValue ( name, env )

  1. Let boundName be the string-concatenation of "->" and name.
  2. While env is not null,
    1. Let envRec be env's EnvironmentRecord.
    2. If envRec is a declarative EnvironmentRecord, then
      1. Let exists be ! envRec.HasBinding(boundName).
      2. If exists is true, return ? envRec.GetBindingValue(boundName, true).
      3. Let env be the value of env's outer environment reference.
  3. Return undefined.

4.5FindInstanceVariable ( obj, desc )

  1. Assert: desc is a HiddenMemberDescriptor Record.
  2. Assert: GetHiddenMemberDescriptorKind(desc) is "var".
  3. If Type(obj) is not Object, throw a TypeError exception.
  4. For each element record of obj.[[InstanceVariables]], do
    1. If record.[[Key]] is desc.[[InstanceVariableKey]], return record.
  5. Throw a TypeError exception.

5References

A Reference is a resolved name or property binding. A Reference consists of three components, the base value component, the referenced name component, and the Boolean-valued strict reference flag. The base value component is either undefined, an Object, a Boolean, a String, a Symbol, a Number, or an Environment Record. A base value component of undefined indicates that the Reference could not be resolved to a binding. The referenced name component is a String, a Symbol, or a HiddenMemberDescriptor.

5.1IsHiddenReference ( V )

  1. Assert: Type(V) is Reference.
  2. If the referenced name component of V is a HiddenMemberDescriptor record, return true.
  3. Return false.

5.2GetValue ( V )

  1. ReturnIfAbrupt(V).
  2. If Type(V) is not Reference, return V.
  3. Let base be GetBase(V).
  4. If IsUnresolvableReference(V) is true, throw a ReferenceError exception.
  5. If IsHiddenReference(V) is true, return GetHiddenValue(V).
  6. If IsPropertyReference(V) is true, then
    1. If HasPrimitiveBase(V) is true, then
      1. Assert: In this case, base will never be undefined or null.
      2. Set base to ! ToObject(base).
    2. Return ? base.[[Get]](GetReferencedName(V), GetThisValue(V)).
  7. Else base must be an Environment Record,
    1. Return ? base.GetBindingValue(GetReferencedName(V), IsStrictReference(V)) (see 8.1.1).

5.3PutValue ( V, W )

  1. ReturnIfAbrupt(V).
  2. ReturnIfAbrupt(W).
  3. If Type(V) is not Reference, throw a ReferenceError exception.
  4. Let base be GetBase(V).
  5. If IsUnresolvableReference(V) is true, then
    1. If IsStrictReference(V) is true, then
      1. Throw a ReferenceError exception.
    2. Let globalObj be GetGlobalObject().
    3. Return ? Set(globalObj, GetReferencedName(V), W, false).
  6. Else if IsHiddenReference(V) is true, return SetHiddenValue(V, W).
  7. Else if IsPropertyReference(V) is true, then
    1. If HasPrimitiveBase(V) is true, then
      1. Assert: In this case, base will never be undefined or null.
      2. Set base to ! ToObject(base).
    2. Let succeeded be ? base.[[Set]](GetReferencedName(V), W, GetThisValue(V)).
    3. If succeeded is false and IsStrictReference(V) is true, throw a TypeError exception.
    4. Return.
  8. Else base must be an Environment Record,
    1. Return ? base.SetMutableBinding(GetReferencedName(V), W, IsStrictReference(V)) (see 8.1.1).

5.4GetHiddenValue ( V )

  1. Assert: Type(V) is Reference.
  2. Let hmd be GetReferencedName(V).
  3. Assert: Type(hmd) is HiddenMemberDescriptor.
  4. Let kind be GetHiddenMemberDescriptorKind(hmd).
  5. If kind is "method", return desc.[[Value]].
  6. Let base be GetBase(V).
  7. If kind is "accessor", then
    1. Let getter be desc.[[Get]].
    2. If getter is undefined, return undefined.
    3. Return ? Call(getter, base).
  8. Else kind must be "var",
    1. Let var be ? FindInstanceVariable(base, desc).
    2. Return var.[[Value]].

5.5SetHiddenValue ( V, W )

  1. Assert: Type(V) is Reference.
  2. Let hmd be GetReferencedName(V).
  3. Assert: hmd is a HiddenMemberDescriptor Record.
  4. Let kind be GetHiddenMemberDescriptorKind(hmd).
  5. Assert: kind will never be "method".
  6. Let base be GetBase(V).
  7. If kind is "accessor", then
    1. Let setter be desc.[[Set]].
    2. Assert: IsCallable(setter) is true.
    3. Return ? Call(setter, base, « W »).
  8. Else kind must be "var",
    1. Let var be ? FindInstanceVariable(base, desc).
    2. Set var.[[Value]] to W.
Note
Early error rules prevent assignment to hidden references if there is no hidden set accessor method or instance variable in scope.

ACopyright & Software License

Copyright Notice

© 2018 Kevin Smith, Allen Wirfs-Brock

Software License

All Software contained in this document ("Software") is protected by copyright and is being made available under the "BSD License", included below. This Software may be subject to third party rights (rights from parties other than Ecma International), including patent rights, and no licenses under such third party rights are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT http://www.ecma-international.org/memento/codeofconduct.htm FOR INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.