Stage 3 Draft / December 11, 2018

Public and private instance fields proposal

Introduction

This document attempts to integrate the public fields and private fields proposals into a single, coherent, orthogonal whole. See the explainer for an overview.

1Syntax

1.1Lexical Grammar

PrivateName::#IdentifierName CommonToken::IdentifierName Punctuator NumericLiteral StringLiteral Template PrivateName

1.2New Syntactic Grammar Productions

FieldDefinition[Yield, Await]:ClassElementName[?Yield, ?Await]Initializer[In, ~Yield, ~Await]opt ClassElementName[Yield, Await]:PropertyName[?Yield, ?Await] PrivateName

1.3Updated Syntactic Grammar Productions

ClassElement[Yield, Await]:MethodDefinition[?Yield, ?Await] staticMethodDefinition[?Yield, ?Await] FieldDefinition[?Yield, ?Await]; ; MemberExpression[Yield, Await]:PrimaryExpression[?Yield, ?Await] MemberExpression[?Yield, ?Await][Expression[+In, ?Yield, ?Await]] MemberExpression[?Yield, ?Await].IdentifierName MemberExpression[?Yield, ?Await]TemplateLiteral[?Yield, ?Await] SuperProperty[?Yield, ?Await] MetaProperty newMemberExpression[?Yield, ?Await]Arguments[?Yield, ?Await] MemberExpression[?Yield, ?Await].PrivateName 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]TemplateLiteral[?Yield, ?Await] CallExpression[?Yield, ?Await].PrivateName

1.4Static Semantics: Early Errors

FieldDefinition:ClassElementNameInitializeropt ClassBody:ClassElementList ClassElement:FieldDefinition; ClassElementName:PrivateName;
  • It is a Syntax Error if StringValue of PrivateName is "#constructor".
Note 1

These static rules have been modified to produce an early error if the delete operator is applied to a private reference.

UnaryExpression:deleteUnaryExpression Note 2

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

Editor's Note
Private fields may not be deleted in any case. There are only ever private names defined inside class bodies. Inside of a class body, code will be in strict mode, and the above rule applies. Outside of a class body, there will be no private names defined, so the below rule will apply.
ScriptBody:StatementList ModuleBody:ModuleItemList Editor's Note
References to PrivateNames which are not lexically present cause an early error.

1.4.1Static Semantics: AllPrivateNamesValid

AllPrivateNamesValid is an abstract operation which takes names as an argument. MemberExpression[Yield, Await]:MemberExpression[?Yield, ?Await].PrivateName
  1. If StringValue of PrivateName is in names, return true.
  2. Return false.
CallExpression[Yield, Await]:CallExpression[?Yield, ?Await].PrivateName
  1. If StringValue of PrivateName is in names, return true.
  2. Return false.
ClassBody[Yield, Await]:ClassElementList[?Yield, ?Await]
  1. Let newNames be the concatenation of names with PrivateBoundNames of ClassBody.
  2. Return AllPrivateNamesValid of ClassElementList with the argument newNames.
For all other grammatical productions, recurse on subexpressions/substatements, passing in the names of the caller. If all pieces return true, then return true. If any returns false, return false. Editor's Note
TODO: Elaborate the preceding paragraph with spec text inserted in each relevant place

2Modified algorithms

2.1Static Semantics: PropName

FieldDefinition:ClassElementNameInitializeropt
  1. Return PropName of ClassElementName.
ClassElementName[Yield, Await]:PropertyName[?Yield, ?Await]
  1. Return PropName of PropertyName.
ClassElementName[Yield, Await]:PrivateName
  1. Return empty.

2.2Runtime Semantics: Evaluation

ClassElementName[Yield, Await]:PropertyName[?Yield, ?Await]
  1. Return the result of evaluating PropertyName.
ClassElementName[Yield, Await]:PrivateName
  1. Let bindingName be StringValue of PrivateName.
  2. Let field be NewPrivateName(bindingName).
  3. Let scope be the running execution context's PrivateNameEnvironment.
  4. Let scopeEnvRec be scope's EnvironmentRecord.
  5. Perform ! scopeEnvRec.InitializeBinding(bindingName, field).
  6. Return field.
Editor's Note
Each time a class declaration executes, distinct internal Private Names are created. This means, that they cannot directly access each other's private state if a method of one is called with the other as a receiver.

2.3Runtime Semantics: ClassElementEvaluation

With parameters object and enumerable.

ClassElement:FieldDefinition;
  1. Return ClassFieldDefinitionEvaluation of FieldDefinition with parameter object.
ClassElement:MethodDefinition ClassElement:staticMethodDefinition
  1. Perform ? PropertyDefinitionEvaluation with parameters object and enumerable.
  2. Return empty.

2.4Runtime Semantics: ClassFieldDefinitionEvaluation

With parameter homeObject.

FieldDefinition:ClassElementNameInitializeropt
  1. Let fieldName be the result of evaluating ClassElementName.
  2. ReturnIfAbrupt(fieldName).
  3. If Initializeropt is present,
    1. Let lex be the Lexical Environment of the running execution context.
    2. Let formalParameterList be an instance of the production FormalParameters:[empty] .
    3. Let initializer be FunctionCreate(Method, formalParameterList, Initializer, lex, true).
    4. Perform MakeMethod(initializer, homeObject).
    5. Let isAnonymousFunctionDefinition be IsAnonymousFunctionDefinition(Initializer).
  4. Else,
    1. Let initializer be empty.
    2. Let isAnonymousFunctionDeclaration be false.
  5. Return a Record { [[Name]]: fieldName, [[Initializer]]: initializer, [[IsAnonymousFunctionDefinition]]: isAnonymousFunctionDefinition }.

2.5Runtime Semantics: EvaluateBody

With parameter functionObject and List argumentsList.

Initializer:=AssignmentExpression
  1. Assert: argumentsList is empty.
  2. Return the result of evaluating AssignmentExpression.
Note
FunctionDeclarationInstantiation would not have any observable behaviour here, so its call is omitted.

2.6SetFunctionName ( F, name [ , prefix ] )

The abstract operation SetFunctionName requires a Function argument F, a String, Symbol, or Private Name argument name and optionally a String argument prefix. This operation adds a name property to F by performing the following steps:

  1. Assert: F is an extensible object that does not have a name own property.
  2. Assert: Type(name) is either Symbol, String, or Private Name.
  3. Assert: If prefix was passed, then Type(prefix) is String.
  4. If Type(name) is Symbol, then
    1. Let description be name's [[Description]] value.
    2. If description is undefined, set name to the empty String.
    3. Else, set name to the concatenation of "[", description, and "]".
  5. Else if name is a Private Name,
    1. Set name to name's [[Description]] value.
  6. If prefix was passed, then
    1. Set name to the concatenation of prefix, code unit 0x0020 (SPACE), and name.
  7. Return ! DefinePropertyOrThrow(F, "name", PropertyDescriptor{[[Value]]: name, [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true}).

2.7DefineField(receiver, fieldRecord)

  1. Assert: Type(receiver) is Object.
  2. Assert: fieldRecord is a Record as created by ClassFieldDefinitionEvaluation.
  3. Let fieldName be fieldRecord.[[Name]].
  4. Let initializer be fieldRecord.[[Initializer]].
  5. If initializer is not empty, then
    1. Let initValue be ? Call(initializer, receiver).
  6. Else, let initValue be undefined.
  7. If fieldRecord.[[IsAnonymousFunctionDefinition]] is true, then
    1. Let hasNameProperty be ? HasOwnProperty(initValue, "name").
    2. If hasNameProperty is false, perform SetFunctionName(initValue, fieldName).
  8. If fieldName is a Private Name,
    1. Perform ? PrivateFieldAdd(fieldName, receiver, initValue).
  9. Else,
    1. Assert: IsPropertyKey(fieldName) is true.
    2. Perform ? CreateDataPropertyOrThrow(receiver, fieldName, initValue).

2.8InitializeInstanceFields ( O, constructor )

  1. Assert: Type ( O ) is Object.
  2. Assert: Assert constructor is an ECMAScript function object.
  3. Let fields be the value of constructor.[[Fields]].
  4. For each item fieldRecord in order from fields,
    1. Perform ? DefineField(O, fields).
  5. Return.
Editor's Note
Private fields are added to the object one by one, interspersed with evaluation of the initializers, following the construction of the receiver. These semantics allow for a later initializer to refer to a previously private field.

2.9Static Semantics: StringValue

PrivateName::#IdentifierName
  1. Return the String value consisting of the sequence of code units corresponding to PrivateName. In determining the sequence any occurrences of \ UnicodeEscapeSequence are first replaced with the code point represented by the UnicodeEscapeSequence and then the code points of the entire PrivateName are converted to code units by UTF16Encoding (10.1.1) each code point.

2.10Static Semantics: PrivateBoundNames

FieldDefinition:ClassElementNameInitializeropt
  1. Return PrivateBoundNames of ClassElementName
ClassElementName:PrivateName
  1. Return a new List containing the StringValue of PrivateName.
ClassElementName:PropertyName
  1. Return a new empty List.
ClassElement:MethodDefinition; ClassElement:staticMethodDefinition; ClassElement:;
  1. Return a new empty List.
ClassElementList:ClassElement
  1. Return PrivateBoundNames of ClassElement.
ClassElementList:ClassElementListClassElement
  1. Let names be PrivateBoundNames of ClassElementList.
  2. Append to names the elements of PrivateBoundNames of ClassElement.
  3. Return names.
ClassBody:ClassElementList
  1. Return PrivateBoundNames of ClassElementList.

2.11Static Semantics: ContainsArguments

IdentifierReference:Identifier
  1. If the StringValue of Identifier is "arguments", return true.
  2. Else, return false.
FunctionDeclaration:functionBindingIdentifier(FormalParameters){FunctionBody} FunctionDeclaration:function(FormalParameters){FunctionBody} FunctionExpression:functionBindingIdentifieropt(FormalParameters){FunctionBody}
  1. Return false.
MethodDefinition:PropertyName(UniqueFormalParameters){FunctionBody} getPropertyName(){FunctionBody} setPropertyName(PropertySetParameterList){FunctionBody}
  1. Return the result of ContainsArguments for PropertyName.
GeneratorMethod:*PropertyName(UniqueFormalParameters){GeneratorBody}
  1. Return the result of ContainsArguments for PropertyName.
GeneratorDeclaration:function*BindingIdentifier(FormalParameters){GeneratorBody} GeneratorDeclaration:function*(FormalParameters){GeneratorBody} GeneratorExpression:function*BindingIdentifieropt(FormalParameters){GeneratorBody}
  1. Return false.
ClassBody:ClassElementList
  1. Return false.
AsyncMethod:async[no LineTerminator here]PropertyName(UniqueFormalParameters){AsyncFunctionBody}
  1. Return the result of ContainsArguments for PropertyName.
AsyncFunctionDeclaration:async[no LineTerminator here]functionBindingIdentifier(FormalParameters){AsyncFunctionBody} AsyncFunctionDeclaration:async[no LineTerminator here]function(FormalParameters){AsyncFunctionBody} AsyncFunctionExpression:async[no LineTerminator here]function(FormalParameters){AsyncFunctionBody} AsyncFunctionExpression:async[no LineTerminator here]functionBindingIdentifier(FormalParameters){AsyncFunctionBody}
  1. Return false.
For all other grammatical productions, recurse on all nonterminals. If any piece returns true, then return true. Otherwise return false. Editor's Note
TODO: Elaborate the preceding paragraph with spec text inserted in each relevant place

2.12Class Definitions

2.12.1Static Semantics: IsStatic

ClassElement:FieldDefinition
  1. Return false.

2.12.2Runtime Semantics: ClassDefinitionEvaluation

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. Let outerPrivateEnvironment be the PrivateNameEnvironment of the running execution context.
  6. Let classPrivateEnvironment be NewDeclarativeEnvironment(outerPrivateEnvironment).
  7. Let classPrivateEnvRec be classPrivateEnvironment's EnvironmentRecord.
  8. If ClassBodyopt is present, then
    1. For each element dn of the PrivateBoundNames of ClassBodyopt,
      1. Perform classPrivateEnvRec.CreateImmutableBinding(dn, true).
  9. If ClassHeritageopt is not present, then
    1. Let protoParent be the intrinsic object %ObjectPrototype%.
    2. Let constructorParent be the intrinsic object %FunctionPrototype%.
  10. Else,
    1. Set the running execution context's LexicalEnvironment to classScope.
    2. NOTE: The running execution context's PrivateNameEnvironment is outerPrivateEnvironment when evaluating ClassHeritage.
    3. Let superclass be the result of evaluating ClassHeritage.
    4. Set the running execution context's LexicalEnvironment to lex.
    5. ReturnIfAbrupt(superclass).
    6. If superclass is null, then
      1. Let protoParent be null.
      2. Let constructorParent be the intrinsic object %FunctionPrototype%.
    7. Else if IsConstructor(superclass) is false, throw a TypeError exception.
    8. 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.
  11. Let proto be ObjectCreate(protoParent).
  12. If ClassBodyopt is not present, let constructor be empty.
  13. Else, let constructor be ConstructorMethod of ClassBody.
  14. If constructor is empty, then
    1. If ClassHeritageopt is present and protoParent is not null, then
      1. Let constructor be the result of parsing the source text
        constructor(... args){ super (...args);}
        using the syntactic grammar with the goal symbol MethodDefinition[~Yield].
    2. Else,
      1. Let constructor be the result of parsing the source text
        constructor( ){ }
        using the syntactic grammar with the goal symbol MethodDefinition[~Yield].
  15. Set the running execution context's LexicalEnvironment to classScope.
  16. Set the running execution context's PrivateNameEnvironment to classPrivateEnvironment.
  17. Let constructorInfo be the result of performing DefineMethod for constructor with arguments proto and constructorParent as the optional functionPrototype argument.
  18. Assert: constructorInfo is not an abrupt completion.
  19. Let F be constructorInfo.[[Closure]].
  20. If ClassHeritageopt is present and protoParent is not null, then set F.[[ConstructorKind]] to "derived".
  21. Perform MakeConstructor(F, false, proto).
  22. Perform MakeClassConstructor(F).
  23. Perform CreateMethodProperty(proto, "constructor", F).
  24. If ClassBodyopt is not present, let methodselements be a new empty List.
  25. Else, let methodselements be NonConstructorMethodDefinitions of ClassBody.
  26. Let instanceFields be a new empty List.
  27. For each ClassElement me in order from methodselements
    1. If IsStatic of me is false, then
      1. Let field be the result of performing PropertyDefinitionEvaluation for mClassElementEvaluation for e with arguments proto and false.
    2. Else,
      1. Let field be the result of performing PropertyDefinitionEvaluation for mClassElementEvaluation for e with arguments F and false.
    3. If field is an abrupt completion, then
      1. Set the running execution context's LexicalEnvironment to lex.
      2. Set the running execution context's PrivateNameEnvironment to outerPrivateEnvironment.
      3. Return Completion(field).
    4. If field is not empty, append field to instanceFields.
  28. Set the running execution context's LexicalEnvironment to lex.
  29. If className is not undefined, then
    1. Perform classScopeEnvRec.InitializeBinding(className, F).
  30. Set F.[[Fields]] to instanceFields.
  31. Set the running execution context's PrivateNameEnvironment to outerPrivateEnvironment.
  32. Return F.

2.13[[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. Let result be InitializeInstanceFields(thisArgument, F).
    3. If result is an abrupt completion, then
      1. Remove calleeContext from execution context stack and restore callerContext as the running execution context.
      2. Return Completion(result).
  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().
Editor's Note
Fields are added by the base class constructor when the super chain reaches up to that, rather than by the subclass constructor when creating the object, in order to be analogous to ES2015 subclassable builtins. See this GitHub thread for more discussion.

2.14The super Keyword

2.14.1Runtime Semantics: Evaluation

SuperCall:superArguments
  1. Let newTarget be GetNewTarget().
  2. If newTarget is undefined, throw a ReferenceError exception.
  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. Let F be thisER.[[FunctionObject]].
  9. Assert: F is an ECMAScript function object.
  10. ReturnPerform ? thisER.BindThisValue(result).
  11. Perform ? InitializeInstanceFields(result, F).
  12. Return result.

2.15The delete Operator

2.15.1Runtime Semantics: Evaluation

UnaryExpression:deleteUnaryExpression
  1. Let ref be the result of evaluating UnaryExpression.
  2. ReturnIfAbrupt(ref).
  3. If Type(ref) is not Reference, return true.
  4. If IsUnresolvableReference(ref) is true, then
    1. Assert: IsStrictReference(ref) is false.
    2. Return true.
  5. If IsPropertyReference(ref) is true, then
    1. Assert: IsPrivateReference(ref) is false.
    2. If IsSuperReference(ref), throw a ReferenceError exception.
    3. Let baseObj be ! ToObject(GetBase(ref)).
    4. Let deleteStatus be ? baseObj.[[Delete]](GetReferencedName(ref)).
    5. If deleteStatus is false and IsStrictReference(ref) is true, throw a TypeError exception.
    6. Return deleteStatus.
  6. Else ref is a Reference to an Environment Record binding,
    1. Let bindings be GetBase(ref).
    2. Return ? bindings.DeleteBinding(GetReferencedName(ref)).
Note

When a delete operator occurs within strict mode code, a SyntaxError exception is thrown if its UnaryExpression is a direct reference to a variable, function argument, or function name. In addition, if a delete operator occurs within strict mode code and the property to be deleted has the attribute { [[Configurable]]: false }, a TypeError exception is thrown.

2.16Runtime Semantics: CreateDynamicFunction( constructor, newTarget, kind, args )

The abstract operation CreateDynamicFunction is called with arguments constructor, newTarget, kind, and args. constructor is the constructor function that is performing this action, newTarget is the constructor that new was initially applied to, kind is either "normal", "generator", or "async", and args is a List containing the actual argument values that were passed to constructor. The following steps are taken:

  1. Assert: The execution context stack has at least two elements.
  2. Let callerContext be the second to top element of the execution context stack.
  3. Let callerRealm be callerContext's Realm.
  4. Let calleeRealm be the current Realm Record.
  5. Perform ? HostEnsureCanCompileStrings(callerRealm, calleeRealm).
  6. If newTarget is undefined, set newTarget to constructor.
  7. If kind is "normal", then
    1. Let goal be the grammar symbol FunctionBody[~Yield, ~Await].
    2. Let parameterGoal be the grammar symbol FormalParameters[~Yield, ~Await].
    3. Let fallbackProto be "%FunctionPrototype%".
  8. Else if kind is "generator", then
    1. Let goal be the grammar symbol GeneratorBody.
    2. Let parameterGoal be the grammar symbol FormalParameters[+Yield, ~Await].
    3. Let fallbackProto be "%Generator%".
  9. Else,
    1. Assert: kind is "async".
    2. Let goal be the grammar symbol AsyncFunctionBody.
    3. Let parameterGoal be the grammar symbol FormalParameters[~Yield, +Await].
    4. Let fallbackProto be "%AsyncFunctionPrototype%".
  10. Let argCount be the number of elements in args.
  11. Let P be the empty String.
  12. If argCount = 0, let bodyText be the empty String.
  13. Else if argCount = 1, let bodyText be args[0].
  14. Else argCount > 1,
    1. Let firstArg be args[0].
    2. Set P to ? ToString(firstArg).
    3. Let k be 1.
    4. Repeat, while k < argCount-1
      1. Let nextArg be args[k].
      2. Let nextArgString be ? ToString(nextArg).
      3. Set P to the result of concatenating the previous value of P, the String "," (a comma), and nextArgString.
      4. Increase k by 1.
    5. Let bodyText be args[k].
  15. Set bodyText to ? ToString(bodyText).
  16. Let parameters be the result of parsing P, interpreted as UTF-16 encoded Unicode text as described in 6.1.4, using parameterGoal as the goal symbol. Throw a SyntaxError exception if the parse fails.
  17. Let body be the result of parsing bodyText, interpreted as UTF-16 encoded Unicode text as described in 6.1.4, using goal as the goal symbol. Throw a SyntaxError exception if the parse fails.
  18. Let strict be ContainsUseStrict of body.
  19. If any static semantics errors are detected for parameters or body, throw a SyntaxError or a ReferenceError exception, depending on the type of the error. If strict is true, the Early Error rules for UniqueFormalParameters:FormalParameters are applied. Parsing and early error detection may be interweaved in an implementation-dependent manner.
  20. If strict is true and IsSimpleParameterList of parameters is false, throw a SyntaxError exception.
  21. If any element of the BoundNames of parameters also occurs in the LexicallyDeclaredNames of body, throw a SyntaxError exception.
  22. If body Contains SuperCall is true, throw a SyntaxError exception.
  23. If parameters Contains SuperCall is true, throw a SyntaxError exception.
  24. If body Contains SuperProperty is true, throw a SyntaxError exception.
  25. If parameters Contains SuperProperty is true, throw a SyntaxError exception.
  26. If kind is "generator", then
    1. If parameters Contains YieldExpression is true, throw a SyntaxError exception.
  27. If kind is "async", then
    1. If parameters Contains AwaitExpression is true, throw a SyntaxError exception.
  28. If strict is true, then
    1. If BoundNames of parameters contains any duplicate elements, throw a SyntaxError exception.
  29. Let privateNames be an empty List.
  30. If AllPrivateNamesValid of body with the argument privateNames is false, throw a SyntaxError exception.
  31. If AllPrivateNamesValid of parameters with the argument privateNames is false, throw a SyntaxError exception.
  32. Let proto be ? GetPrototypeFromConstructor(newTarget, fallbackProto).
  33. Let F be FunctionAllocate(proto, strict, kind).
  34. Let realmF be F.[[Realm]].
  35. Let scope be realmF.[[GlobalEnv]].
  36. Let privateNameScope be a new Lexical Environment.
  37. Perform FunctionInitialize(F, Normal, parameters, body, scope, privateNameScope).
  38. If kind is "generator", then
    1. Let prototype be ObjectCreate(%GeneratorPrototype%).
    2. Perform DefinePropertyOrThrow(F, "prototype", PropertyDescriptor{[[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false}).
  39. Else if kind is "normal", perform MakeConstructor(F).
  40. NOTE: Async functions are not constructable and do not have a [[Construct]] internal method or a "prototype" property.
  41. Perform SetFunctionName(F, "anonymous").
  42. Return F.
Note

A prototype property is created for every non-async function created using CreateDynamicFunction to provide for the possibility that the function will be used as a constructor.

2.17eval ( x )

2.17.1Runtime Semantics: PerformEval ( x, evalRealm, strictCaller, direct )

The abstract operation PerformEval with arguments x, evalRealm, strictCaller, and direct performs the following steps:

  1. Assert: If direct is false, then strictCaller is also false.
  2. If Type(x) is not String, return x.
  3. Let thisEnvRec be ! GetThisEnvironment().
  4. If thisEnvRec is a function Environment Record, then
    1. Let F be thisEnvRec.[[FunctionObject]].
    2. Let inFunction be true.
    3. Let inMethod be thisEnvRec.HasSuperBinding().
    4. If F.[[ConstructorKind]] is "derived", let inDerivedConstructor be true; otherwise, let inDerivedConstructor be false.
  5. Else,
    1. Let inFunction be false.
    2. Let inMethod be false.
    3. Let inDerivedConstructor be false.
  6. Let script be the ECMAScript code that is the result of parsing x, interpreted as UTF-16 encoded Unicode text as described in 6.1.4, for the goal symbol Script. If inFunction is false, additional early error rules from 18.2.1.1.1 are applied. If inMethod is false, additional early error rules from 18.2.1.1.2 are applied. If inDerivedConstructor is false, additional early error rules from 18.2.1.1.3 are applied. If the parse fails, throw a SyntaxError exception. If any early errors are detected, throw a SyntaxError or a ReferenceError exception, depending on the type of the error (but see also clause 16). Parsing and early error detection may be interweaved in an implementation-dependent manner.
  7. If script Contains ScriptBody is false, return undefined.
  8. Let body be the ScriptBody of script.
  9. If strictCaller is true, let strictEval be true.
  10. Else, let strictEval be IsStrict of script.
  11. Let ctx be the running execution context.
  12. NOTE: If direct is true, ctx will be the execution context that performed the direct eval. If direct is false, ctx will be the execution context for the invocation of the eval function.
  13. If direct is true, then
    1. Let lexEnv be NewDeclarativeEnvironment(ctx's LexicalEnvironment).
    2. Let varEnv be ctx's VariableEnvironment.
    3. Let privateNameEnv be ctx's PrivateNameEnvironment.
  14. Else,
    1. Let lexEnv be NewDeclarativeEnvironment(evalRealm.[[GlobalEnv]]).
    2. Let varEnv be evalRealm.[[GlobalEnv]].
    3. Let privateNameEnv be a new Lexical Environment.
  15. If strictEval is true, set varEnv to lexEnv.
  16. If ctx is not already suspended, suspend ctx.
  17. Let evalCxt be a new ECMAScript code execution context.
  18. Set the evalCxt's Function to null.
  19. Set the evalCxt's Realm to evalRealm.
  20. Set the evalCxt's ScriptOrModule to ctx's ScriptOrModule.
  21. Set the evalCxt's VariableEnvironment to varEnv.
  22. Set the evalCxt's LexicalEnvironment to lexEnv.
  23. Set the evalCxt's PrivateNameEnvironment to privateNameEnv.
  24. Push evalCxt on to the execution context stack; evalCxt is now the running execution context.
  25. Let result be EvalDeclarationInstantiation(body, varEnv, lexEnv, privateNameEnvstrictEval).
  26. If result.[[Type]] is normal, then
    1. Set result to the result of evaluating body.
  27. If result.[[Type]] is normal and result.[[Value]] is empty, then
    1. Set result to NormalCompletion(undefined).
  28. Suspend evalCxt and remove it from the execution context stack.
  29. Resume the context that is now on the top of the execution context stack as the running execution context.
  30. Return Completion(result).

2.17.2Additional Early Error Rules for Eval Inside Initializer

These static semantics are applied by PerformEval when a direct eval call occurs inside a class field initializer.

ScriptBody:StatementList

2.17.3Runtime Semantics: EvalDeclarationInstantiation( body, varEnv, lexEnv, privateNameEnv,strict )

When the abstract operation EvalDeclarationInstantiation is called with arguments body, varEnv, lexEnv, privateNameEnv, and strict, the following steps are taken:

  1. Let varNames be the VarDeclaredNames of body.
  2. Let varDeclarations be the VarScopedDeclarations of body.
  3. Let lexEnvRec be lexEnv's EnvironmentRecord.
  4. Let varEnvRec be varEnv's EnvironmentRecord.
  5. If strict is false, then
    1. If varEnvRec is a global Environment Record, then
      1. For each name in varNames, do
        1. If varEnvRec.HasLexicalDeclaration(name) is true, throw a SyntaxError exception.
        2. NOTE: eval will not create a global var declaration that would be shadowed by a global lexical declaration.
    2. Let thisLex be lexEnv.
    3. Assert: The following loop will terminate.
    4. Repeat while thisLex is not the same as varEnv,
      1. Let thisEnvRec be thisLex's EnvironmentRecord.
      2. If thisEnvRec is not an object Environment Record, then
        1. NOTE: The environment of with statements cannot contain any lexical declaration so it doesn't need to be checked for var/let hoisting conflicts.
        2. For each name in varNames, do
          1. If thisEnvRec.HasBinding(name) is true, then
            1. Throw a SyntaxError exception.
            2. NOTE: Annex B.3.5 defines alternate semantics for the above step.
          2. NOTE: A direct eval will not hoist var declaration over a like-named lexical declaration.
      3. Let thisLex be thisLex's outer environment reference.
  6. Let privateNames be an empty List.
  7. Let privateEnv be privateNameEnv.
  8. Repeat while privateEnv is not null,
    1. For each binding named N in privateEnv,
      1. If privateNames does not contain N, append N to privateNames.
    2. Let privateEnv be privateEnv's outer environment reference.
  9. If AllPrivateNamesValid of body with the argument privateNames is false, throw a SyntaxError exception.
  10. Let functionsToInitialize be a new empty List.
  11. Let declaredFunctionNames be a new empty List.
  12. For each d in varDeclarations, in reverse list order do
    1. If d is neither a VariableDeclaration nor a ForBinding nor a BindingIdentifier, then
      1. Assert: d is either a FunctionDeclaration, a GeneratorDeclaration, or an AsyncFunctionDeclaration.
      2. NOTE If there are multiple function declarations for the same name, the last declaration is used.
      3. Let fn be the sole element of the BoundNames of d.
      4. If fn is not an element of declaredFunctionNames, then
        1. If varEnvRec is a global Environment Record, then
          1. Let fnDefinable be ? varEnvRec.CanDeclareGlobalFunction(fn).
          2. If fnDefinable is false, throw a TypeError exception.
        2. Append fn to declaredFunctionNames.
        3. Insert d as the first element of functionsToInitialize.
  13. NOTE: Annex B.3.3.3 adds additional steps at this point.
  14. Let declaredVarNames be a new empty List.
  15. For each d in varDeclarations, do
    1. If d is a VariableDeclaration, a ForBinding, or a BindingIdentifier, then
      1. For each String vn in the BoundNames of d, do
        1. If vn is not an element of declaredFunctionNames, then
          1. If varEnvRec is a global Environment Record, then
            1. Let vnDefinable be ? varEnvRec.CanDeclareGlobalVar(vn).
            2. If vnDefinable is false, throw a TypeError exception.
          2. If vn is not an element of declaredVarNames, then
            1. Append vn to declaredVarNames.
  16. NOTE: No abnormal terminations occur after this algorithm step unless varEnvRec is a global Environment Record and the global object is a Proxy exotic object.
  17. Let lexDeclarations be the LexicallyScopedDeclarations of body.
  18. For each element d in lexDeclarations do
    1. NOTE Lexically declared names are only instantiated here but not initialized.
    2. For each element dn of the BoundNames of d do
      1. If IsConstantDeclaration of d is true, then
        1. Perform ? lexEnvRec.CreateImmutableBinding(dn, true).
      2. Else,
        1. Perform ? lexEnvRec.CreateMutableBinding(dn, false).
  19. For each Parse Node f in functionsToInitialize, do
    1. Let fn be the sole element of the BoundNames of f.
    2. Let fo be the result of performing InstantiateFunctionObject for f with arguments lexEnv and privateNameEnv.
    3. If varEnvRec is a global Environment Record, then
      1. Perform ? varEnvRec.CreateGlobalFunctionBinding(fn, fo, true).
    4. Else,
      1. Let bindingExists be varEnvRec.HasBinding(fn).
      2. If bindingExists is false, then
        1. Let status be ! varEnvRec.CreateMutableBinding(fn, true).
        2. Assert: status is not an abrupt completion because of validation preceding step 12.
        3. Perform ! varEnvRec.InitializeBinding(fn, fo).
      3. Else,
        1. Perform ! varEnvRec.SetMutableBinding(fn, fo, false).
  20. For each String vn in declaredVarNames, in list order do
    1. If varEnvRec is a global Environment Record, then
      1. Perform ? varEnvRec.CreateGlobalVarBinding(vn, true).
    2. Else,
      1. Let bindingExists be varEnvRec.HasBinding(vn).
      2. If bindingExists is false, then
        1. Let status be ! varEnvRec.CreateMutableBinding(vn, true).
        2. Assert: status is not an abrupt completion because of validation preceding step 12.
        3. Perform ! varEnvRec.InitializeBinding(vn, undefined).
  21. Return NormalCompletion(empty).

2.18ModuleDeclarationEnvironmentSetup( module )

The ModuleDeclarationEnvironmentSetup abstract operation is used by InnerModuleInstantiation to initialize the Lexical Environment of the module, including resolving all imported bindings.

This abstract operation performs the following steps:

  1. For each ExportEntry Record e in module.[[IndirectExportEntries]], do
    1. Let resolution be ? module.ResolveExport(e.[[ExportName]], « »).
    2. If resolution is null or "ambiguous", throw a SyntaxError exception.
    3. Assert: resolution is a ResolvedBinding Record.
  2. Assert: All named exports from module are resolvable.
  3. Let realm be module.[[Realm]].
  4. Assert: realm is not undefined.
  5. Let env be NewModuleEnvironment(realm.[[GlobalEnv]]).
  6. Set module.[[Environment]] to env.
  7. Let envRec be env's EnvironmentRecord.
  8. For each ImportEntry Record in in module.[[ImportEntries]], do
    1. Let importedModule be ! HostResolveImportedModule(module, in.[[ModuleRequest]]).
    2. NOTE: The above call cannot fail because imported module requests are a subset of module.[[RequestedModules]], and these have been resolved earlier in this algorithm.
    3. If in.[[ImportName]] is "*", then
      1. Let namespace be ? GetModuleNamespace(importedModule).
      2. Perform ! envRec.CreateImmutableBinding(in.[[LocalName]], true).
      3. Call envRec.InitializeBinding(in.[[LocalName]], namespace).
    4. Else,
      1. Let resolution be ? importedModule.ResolveExport(in.[[ImportName]], « »).
      2. If resolution is null or "ambiguous", throw a SyntaxError exception.
      3. Call envRec.CreateImportBinding(in.[[LocalName]], resolution.[[Module]], resolution.[[BindingName]]).
  9. Let code be module.[[ECMAScriptCode]].
  10. Let varDeclarations be the VarScopedDeclarations of code.
  11. Let declaredVarNames be a new empty List.
  12. For each element d in varDeclarations, do
    1. For each element dn of the BoundNames of d, do
      1. If dn is not an element of declaredVarNames, then
        1. Perform ! envRec.CreateMutableBinding(dn, false).
        2. Call envRec.InitializeBinding(dn, undefined).
        3. Append dn to declaredVarNames.
  13. Let lexDeclarations be the LexicallyScopedDeclarations of code.
  14. Let privateNameEnv be a new Lexical Environment.
  15. For each element d in lexDeclarations, do
    1. For each element dn of the BoundNames of d, do
      1. If IsConstantDeclaration of d is true, then
        1. Perform ! envRec.CreateImmutableBinding(dn, true).
      2. Else,
        1. Perform ! envRec.CreateMutableBinding(dn, false). 1
        2. Let fo be the result of performing InstantiateFunctionObject for d with arguments env and privateNameEnv.
        3. Call envRec.InitializeBinding(dn, fo).

2.19FunctionDeclarationInstantiation ( func, argumentsList )

Note 1

When an execution context is established for evaluating an ECMAScript function a new function Environment Record is created and bindings for each formal parameter are instantiated in that Environment Record. Each declaration in the function body is also instantiated. If the function's formal parameters do not include any default value initializers then the body declarations are instantiated in the same Environment Record as the parameters. If default value parameter initializers exist, a second Environment Record is created for the body declarations. Formal parameters and functions are initialized as part of FunctionDeclarationInstantiation. All other bindings are initialized during evaluation of the function body.

FunctionDeclarationInstantiation is performed as follows using arguments func and argumentsList. func is the function object for which the execution context is being established.

  1. Let calleeContext be the running execution context.
  2. Let env be the LexicalEnvironment of calleeContext.
  3. Let envRec be env's EnvironmentRecord.
  4. Let code be func.[[ECMAScriptCode]].
  5. Let strict be func.[[Strict]].
  6. Let formals be func.[[FormalParameters]].
  7. Let parameterNames be the BoundNames of formals.
  8. If parameterNames has any duplicate entries, let hasDuplicates be true. Otherwise, let hasDuplicates be false.
  9. Let simpleParameterList be IsSimpleParameterList of formals.
  10. Let hasParameterExpressions be ContainsExpression of formals.
  11. Let varNames be the VarDeclaredNames of code.
  12. Let varDeclarations be the VarScopedDeclarations of code.
  13. Let lexicalNames be the LexicallyDeclaredNames of code.
  14. Let functionNames be a new empty List.
  15. Let functionsToInitialize be a new empty List.
  16. For each d in varDeclarations, in reverse list order, do
    1. If d is neither a VariableDeclaration nor a ForBinding nor a BindingIdentifier, then
      1. Assert: d is either a FunctionDeclaration, a GeneratorDeclaration, an AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration.
      2. Let fn be the sole element of the BoundNames of d.
      3. If fn is not an element of functionNames, then
        1. Insert fn as the first element of functionNames.
        2. NOTE: If there are multiple function declarations for the same name, the last declaration is used.
        3. Insert d as the first element of functionsToInitialize.
  17. Let argumentsObjectNeeded be true.
  18. If func.[[ThisMode]] is lexical, then
    1. NOTE: Arrow functions never have an arguments objects.
    2. Set argumentsObjectNeeded to false.
  19. Else if "arguments" is an element of parameterNames, then
    1. Set argumentsObjectNeeded to false.
  20. Else if hasParameterExpressions is false, then
    1. If "arguments" is an element of functionNames or if "arguments" is an element of lexicalNames, then
      1. Set argumentsObjectNeeded to false.
  21. For each String paramName in parameterNames, do
    1. Let alreadyDeclared be envRec.HasBinding(paramName).
    2. NOTE: Early errors ensure that duplicate parameter names can only occur in non-strict functions that do not have parameter default values or rest parameters.
    3. If alreadyDeclared is false, then
      1. Perform ! envRec.CreateMutableBinding(paramName, false).
      2. If hasDuplicates is true, then
        1. Perform ! envRec.InitializeBinding(paramName, undefined).
  22. If argumentsObjectNeeded is true, then
    1. If strict is true or if simpleParameterList is false, then
      1. Let ao be CreateUnmappedArgumentsObject(argumentsList).
    2. Else,
      1. NOTE: mapped argument object is only provided for non-strict functions that don't have a rest parameter, any parameter default value initializers, or any destructured parameters.
      2. Let ao be CreateMappedArgumentsObject(func, formals, argumentsList, envRec).
    3. If strict is true, then
      1. Perform ! envRec.CreateImmutableBinding("arguments", false).
    4. Else,
      1. Perform ! envRec.CreateMutableBinding("arguments", false).
    5. Call envRec.InitializeBinding("arguments", ao).
    6. Let parameterBindings be a new List of parameterNames with "arguments" appended.
  23. Else,
    1. Let parameterBindings be parameterNames.
  24. Let iteratorRecord be CreateListIteratorRecord(argumentsList).
  25. If hasDuplicates is true, then
    1. Perform ? IteratorBindingInitialization for formals with iteratorRecord and undefined as arguments.
  26. Else,
    1. Perform ? IteratorBindingInitialization for formals with iteratorRecord and env as arguments.
  27. If hasParameterExpressions is false, then
    1. NOTE: Only a single lexical environment is needed for the parameters and top-level vars.
    2. Let instantiatedVarNames be a copy of the List parameterBindings.
    3. For each n in varNames, do
      1. If n is not an element of instantiatedVarNames, then
        1. Append n to instantiatedVarNames.
        2. Perform ! envRec.CreateMutableBinding(n, false).
        3. Call envRec.InitializeBinding(n, undefined).
    4. Let varEnv be env.
    5. Let varEnvRec be envRec.
  28. Else,
    1. NOTE: A separate Environment Record is needed to ensure that closures created by expressions in the formal parameter list do not have visibility of declarations in the function body.
    2. Let varEnv be NewDeclarativeEnvironment(env).
    3. Let varEnvRec be varEnv's EnvironmentRecord.
    4. Set the VariableEnvironment of calleeContext to varEnv.
    5. Let instantiatedVarNames be a new empty List.
    6. For each n in varNames, do
      1. If n is not an element of instantiatedVarNames, then
        1. Append n to instantiatedVarNames.
        2. Perform ! varEnvRec.CreateMutableBinding(n, false).
        3. If n is not an element of parameterBindings or if n is an element of functionNames, let initialValue be undefined.
        4. Else,
          1. Let initialValue be ! envRec.GetBindingValue(n, false).
        5. Call varEnvRec.InitializeBinding(n, initialValue).
        6. NOTE: vars whose names are the same as a formal parameter, initially have the same value as the corresponding initialized parameter.
  29. NOTE: Annex B.3.3.1 adds additional steps at this point.
  30. If strict is false, then
    1. Let lexEnv be NewDeclarativeEnvironment(varEnv).
    2. NOTE: Non-strict functions use a separate lexical Environment Record for top-level lexical declarations so that a direct eval can determine whether any var scoped declarations introduced by the eval code conflict with pre-existing top-level lexically scoped declarations. This is not needed for strict functions because a strict direct eval always places all declarations into a new Environment Record.
  31. Else, let lexEnv be varEnv.
  32. Let lexEnvRec be lexEnv's EnvironmentRecord.
  33. Set the LexicalEnvironment of calleeContext to lexEnv.
  34. Let lexDeclarations be the LexicallyScopedDeclarations of code.
  35. For each element d in lexDeclarations, do
    1. NOTE: A lexically declared name cannot be the same as a function/generator declaration, formal parameter, or a var name. Lexically declared names are only instantiated here but not initialized.
    2. For each element dn of the BoundNames of d, do
      1. If IsConstantDeclaration of d is true, then
        1. Perform ! lexEnvRec.CreateImmutableBinding(dn, true).
      2. Else,
        1. Perform ! lexEnvRec.CreateMutableBinding(dn, false).
  36. Let privateNameEnv be the PrivateNameEnvironment of calleeContext.
  37. For each Parse Node f in functionsToInitialize, do
    1. Let fn be the sole element of the BoundNames of f.
    2. Let fo be the result of performing InstantiateFunctionObject for f with arguments lexEnv and privateNameEnv.
    3. Perform ! varEnvRec.SetMutableBinding(fn, fo, false).
  38. Return NormalCompletion(empty).
Note 2

B.3.3 provides an extension to the above algorithm that is necessary for backwards compatibility with web browser implementations of ECMAScript that predate ECMAScript 2015.

Note 3

Parameter Initializers may contain direct eval expressions. Any top level declarations of such evals are only visible to the eval code (10.2). The creation of the environment for such declarations is described in 14.1.19.

2.20Runtime Semantics: BlockDeclarationInstantiation( code, env )

Note

When a Block or CaseBlock is evaluated a new declarative Environment Record is created and bindings for each block scoped variable, constant, function, or class declared in the block are instantiated in the Environment Record.

BlockDeclarationInstantiation is performed as follows using arguments code and env. code is the Parse Node corresponding to the body of the block. env is the Lexical Environment in which bindings are to be created.

  1. Let envRec be env's EnvironmentRecord.
  2. Assert: envRec is a declarative Environment Record.
  3. Let declarations be the LexicallyScopedDeclarations of code.
  4. Let privateNameEnv be the running execution context's PrivateNameEnvironment.
  5. For each element d in declarations, do
    1. For each element dn of the BoundNames of d, do
      1. If IsConstantDeclaration of d is true, then
        1. Perform ! envRec.CreateImmutableBinding(dn, true).
      2. Else,
        1. Perform ! envRec.CreateMutableBinding(dn, false).
    2. If d is a FunctionDeclaration, a GeneratorDeclaration, an AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration, then
      1. Let fn be the sole element of the BoundNames of d.
      2. Let fo be the result of performing InstantiateFunctionObject for d with arguments env and privateNameEnv.
      3. Perform envRec.InitializeBinding(fn, fo).

2.21Runtime Semantics: Evaluation

ArrowFunction:ArrowParameters=>ConciseBody
  1. If the function code for this ArrowFunction is strict mode code, let strict be true. Otherwise let strict be false.
  2. Let scope be the LexicalEnvironment of the running execution context.
  3. Let privateNameScope be the PrivateNameEnvironment of the running execution context.
  4. Let parameters be CoveredFormalsList of ArrowParameters.
  5. Let closure be FunctionCreate(Arrow, parameters, ConciseBody, scope, privateNameScope, strict).
  6. Return closure.
GeneratorExpression:function*(FormalParameters){GeneratorBody}
  1. If the function code for this GeneratorExpression is strict mode code, let strict be true. Otherwise let strict be false.
  2. Let scope be the LexicalEnvironment of the running execution context.
  3. Let privateNameScope be the PrivateNameEnvironment of the running execution context.
  4. Let closure be GeneratorFunctionCreate(Normal, FormalParameters, GeneratorBody, scope, privateNameScope, strict).
  5. Let prototype be ObjectCreate(%GeneratorPrototype%).
  6. Perform DefinePropertyOrThrow(closure, "prototype", PropertyDescriptor{[[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false}).
  7. Return closure.
GeneratorExpression:function*BindingIdentifier(FormalParameters){GeneratorBody}
  1. If the function code for this GeneratorExpression is strict mode code, let strict be true. Otherwise let strict be false.
  2. Let scope be the running execution context's LexicalEnvironment.
  3. Let privateNameScope be the PrivateNameEnvironment of the running execution context.
  4. Let funcEnv be NewDeclarativeEnvironment(scope).
  5. Let envRec be funcEnv's EnvironmentRecord.
  6. Let name be StringValue of BindingIdentifier.
  7. Perform envRec.CreateImmutableBinding(name, false).
  8. Let closure be GeneratorFunctionCreate(Normal, FormalParameters, GeneratorBody, funcEnv, privateNameScope, strict).
  9. Let prototype be ObjectCreate(%GeneratorPrototype%).
  10. Perform DefinePropertyOrThrow(closure, "prototype", PropertyDescriptor{[[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false}).
  11. Perform SetFunctionName(closure, name).
  12. Perform envRec.InitializeBinding(name, closure).
  13. Return closure.
AsyncGeneratorExpression:async[no LineTerminator here]function*(FormalParameters){AsyncGeneratorBody}
  1. If the function code for this AsyncGeneratorExpression is strict mode code, let strict be true. Otherwise let strict be false.
  2. Let scope be the LexicalEnvironment of the running execution context.
  3. Let privateNameScope be the PrivateNameEnvironment of the running execution context.
  4. Let closure be ! AsyncGeneratorFunctionCreate(Normal, FormalParameters, AsyncGeneratorBody, scope, strict).
  5. Let prototype be ! ObjectCreate(%AsyncGeneratorPrototype%).
  6. Perform ! DefinePropertyOrThrow(closure, "prototype", PropertyDescriptor{[[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false}).
  7. Return closure.
AsyncGeneratorExpression:async[no LineTerminator here]function*BindingIdentifier(FormalParameters){AsyncGeneratorBody}
  1. If the function code for this AsyncGeneratorExpression is strict mode code, let strict be true. Otherwise let strict be false.
  2. Let scope be the running execution context's LexicalEnvironment.
  3. Let privateNameScope be the PrivateNameEnvironment of the running execution context.
  4. Let funcEnv be ! NewDeclarativeEnvironment(scope).
  5. Let envRec be funcEnv's EnvironmentRecord.
  6. Let name be StringValue of BindingIdentifier.
  7. Perform ! envRec.CreateImmutableBinding(name).
  8. Let closure be ! AsyncGeneratorFunctionCreate(Normal, FormalParameters, AsyncGeneratorBody, funcEnv, privateNameScope, strict).
  9. Let prototype be ! ObjectCreate(%AsyncGeneratorPrototype%).
  10. Perform ! DefinePropertyOrThrow(closure, "prototype", PropertyDescriptor{[[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false}).
  11. Perform ! SetFunctionName(closure, name).
  12. Perform ! envRec.InitializeBinding(name, closure).
  13. Return closure.
AsyncGeneratorExpression:async[no LineTerminator here]function*(FormalParameters){AsyncGeneratorBody}
  1. If the function code for this AsyncGeneratorExpression is strict mode code, let strict be true. Otherwise let strict be false.
  2. Let scope be the LexicalEnvironment of the running execution context.
  3. Let privateNameScope be the PrivateNameEnvironment of the running execution context.
  4. Let closure be ! AsyncGeneratorFunctionCreate(Normal, FormalParameters, AsyncGeneratorBody, scope, privateNameScope, strict).
  5. Let prototype be ! ObjectCreate(%AsyncGeneratorPrototype%).
  6. Perform ! DefinePropertyOrThrow(closure, "prototype", PropertyDescriptor{[[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false}).
  7. Return closure.
AsyncGeneratorExpression:async[no LineTerminator here]function*BindingIdentifier(FormalParameters){AsyncGeneratorBody}
  1. If the function code for this AsyncGeneratorExpression is strict mode code, let strict be true. Otherwise let strict be false.
  2. Let scope be the running execution context's LexicalEnvironment.
  3. Let privateNameScope be the PrivateNameEnvironment of the running execution context.
  4. Let funcEnv be ! NewDeclarativeEnvironment(scope).
  5. Let envRec be funcEnv's EnvironmentRecord.
  6. Let name be StringValue of BindingIdentifier.
  7. Perform ! envRec.CreateImmutableBinding(name).
  8. Let closure be ! AsyncGeneratorFunctionCreate(Normal, FormalParameters, AsyncGeneratorBody, funcEnv, privateNameScope, strict).
  9. Let prototype be ! ObjectCreate(%AsyncGeneratorPrototype%).
  10. Perform ! DefinePropertyOrThrow(closure, "prototype", PropertyDescriptor{[[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false}).
  11. Perform ! SetFunctionName(closure, name).
  12. Perform ! envRec.InitializeBinding(name, closure).
  13. Return closure.
AsyncFunctionExpression:async[no LineTerminator here]function(FormalParameters){AsyncFunctionBody}
  1. If the function code for AsyncFunctionExpression is strict mode code, let strict be true. Otherwise let strict be false.
  2. Let scope be the LexicalEnvironment of the running execution context.
  3. Let privateNameScope be the PrivateNameEnvironment of the running execution context.
  4. Let closure be ! AsyncFunctionCreate(Normal, FormalParameters, AsyncFunctionBody, scope, privateNameScope, strict).
  5. Return closure.
AsyncFunctionExpression:async[no LineTerminator here]functionBindingIdentifier(FormalParameters){AsyncFunctionBody}
  1. If the function code for AsyncFunctionExpression is strict mode code, let strict be true. Otherwise let strict be false.
  2. Let scope be the LexicalEnvironment of the running execution context.
  3. Let privateNameScope be the PrivateNameEnvironment of the running execution context.
  4. Let funcEnv be ! NewDeclarativeEnvironment(scope).
  5. Let envRec be funcEnv's EnvironmentRecord.
  6. Let name be StringValue of BindingIdentifier.
  7. Perform ! envRec.CreateImmutableBinding(name).
  8. Let closure be ! AsyncFunctionCreate(Normal, FormalParameters, AsyncFunctionBody, funcEnv, privateNameScope, strict).
  9. Perform ! SetFunctionName(closure, name).
  10. Perform ! envRec.InitializeBinding(name, closure).
  11. Return closure.
AsyncArrowFunction:async[no LineTerminator here]AsyncArrowBindingIdentifier[no LineTerminator here]=>AsyncConciseBody
  1. If the function code for this AsyncArrowFunction is strict mode code, let strict be true. Otherwise, let strict be false.
  2. Let scope be the LexicalEnvironment of the running execution context.
  3. Let privateNameScope be the PrivateNameEnvironment of the running execution context.
  4. Let parameters be AsyncArrowBindingIdentifier.
  5. Let closure be ! AsyncFunctionCreate(Arrow, parameters, AsyncConciseBody, scope, privateNameScope, strict).
  6. Return closure.
AsyncArrowFunction:CoverCallExpressionAndAsyncArrowHead[no LineTerminator here]=>AsyncConciseBody
  1. If the function code for this AsyncArrowFunction is strict mode code, let strict be true. Otherwise, let strict be false.
  2. Let scope be the LexicalEnvironment of the running execution context.
  3. Let privateNameScope be the PrivateNameEnvironment of the running execution context.
  4. Let head be CoveredAsyncArrowHead of CoverCallExpressionAndAsyncArrowHead.
  5. Let parameters be the ArrowFormalParameters of head.
  6. Let closure be ! AsyncFunctionCreate(Arrow, parameters, AsyncConciseBody, scope, privateNameScope, strict).
  7. Return closure.

2.22Runtime Semantics: DefineMethod

With parameters object and optional parameter functionPrototype.

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 privateNameScope be the PrivateNameEnvironment of the running execution context.
  6. If functionPrototype is present as a parameter, then
    1. Let kind be Normal.
    2. Let prototype be functionPrototype.
  7. Else,
    1. Let kind be Method.
    2. Let prototype be the intrinsic object %FunctionPrototype%.
  8. Let closure be FunctionCreate(kind, UniqueFormalParameters, FunctionBody, scope, privateNameScope, strict, prototype).
  9. Perform MakeMethod(closure, object).
  10. Return the Record{[[Key]]: propKey, [[Closure]]: closure}.

2.23Runtime Semantics: PropertyDefinitionEvaluation

With parameters object and enumerable.

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 privateNameScope be the PrivateNameEnvironment of the running execution context.
  6. Let formalParameterList be an instance of the production FormalParameters:[empty] .
  7. Let closure be FunctionCreate(Method, formalParameterList, FunctionBody, scope, privateNameScope, strict).
  8. Perform MakeMethod(closure, object).
  9. Perform SetFunctionName(closure, propKey, "get").
  10. Let desc be the PropertyDescriptor{[[Get]]: closure, [[Enumerable]]: enumerable, [[Configurable]]: true}.
  11. Return ? DefinePropertyOrThrow(object, propKey, desc).
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 privateNameScope be the PrivateNameEnvironment of the running execution context.
  6. Let closure be FunctionCreate(Method, PropertySetParameterList, FunctionBody, scope, privateNameScope, strict).
  7. Perform MakeMethod(closure, object).
  8. Perform SetFunctionName(closure, propKey, "set").
  9. Let desc be the PropertyDescriptor{[[Set]]: closure, [[Enumerable]]: enumerable, [[Configurable]]: true}.
  10. Return ? DefinePropertyOrThrow(object, propKey, desc).
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 privateNameScope be the PrivateNameEnvironment of the running execution context.
  6. Let closure be GeneratorFunctionCreate(Method, UniqueFormalParameters, GeneratorBody, scope, privateNameScope, strict).
  7. Perform MakeMethod(closure, object).
  8. Let prototype be ObjectCreate(%GeneratorPrototype%).
  9. Perform DefinePropertyOrThrow(closure, "prototype", PropertyDescriptor{[[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false}).
  10. Perform SetFunctionName(closure, propKey).
  11. Let desc be the PropertyDescriptor{[[Value]]: closure, [[Writable]]: true, [[Enumerable]]: enumerable, [[Configurable]]: true}.
  12. ReturnPerformDefinePropertyOrThrow(object, propKey, desc).
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 privateNameScope be the PrivateNameEnvironment of the running execution context.
  6. Let closure be ! AsyncGeneratorFunctionCreate(Method, UniqueFormalParameters, AsyncGeneratorBody, scope, privateNameScope, strict).
  7. Perform ! MakeMethod(closure, object).
  8. Let prototype be ! ObjectCreate(%AsyncGeneratorPrototype%).
  9. Perform ! DefinePropertyOrThrow(closure, "prototype", PropertyDescriptor{[[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false}).
  10. Perform ! SetFunctionName(closure, propKey).
  11. Let desc be PropertyDescriptor{[[Value]]: closure, [[Writable]]: true, [[Enumerable]]: enumerable, [[Configurable]]: true}.
  12. ReturnPerformDefinePropertyOrThrow(object, propKey, desc).
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 privateNameScope be the PrivateNameEnvironment of the running execution context.
  6. Let closure be ! AsyncFunctionCreate(Method, UniqueFormalParameters, AsyncFunctionBody, scope, privateNameScope, strict).
  7. Perform ! MakeMethod(closure, object).
  8. Perform ! SetFunctionName(closure, propKey).
  9. Let desc be the PropertyDescriptor{[[Value]]: closure, [[Writable]]: true, [[Enumerable]]: enumerable, [[Configurable]]: true}.
  10. ReturnPerformDefinePropertyOrThrow(object, propKey, desc).

3Private Names and references

The Private Name specification type is used to describe a globally unique identifier which represents a private field name. A private name may be installed on any ECMAScript object with the PrivateFieldAdd internal algorithm, and then read or written using PrivateFieldGet and PrivateFieldSet.

Each PrivateName value immutably holds an associated value called [[Description]] that is a String value.

All ECMAScript objects have a new additional internal slot, [[PrivateFieldValues]], which is a List of Records of the form { [[PrivateName]]: Private Name, [[PrivateFieldValue]]: ECMAScript value }. This List represents the values of the private fields for the object. All objects, including Proxies and all host environment-provided objects, have this internal slot, but primitives such as Numbers do not.

Editor's Note

Private fields are designed to have semantics analogous to WeakMaps. However, the implied garbage collection semantics are weaker: If all the references to a WeakMap are inaccessible, but there is still a reference to a key which was in the WeakMap, one would expect the value to be eventually collected. However, PrivateNameIdentifiers specifically do not have this connotation: because the reference from the Identifier to the Value is in a Record which the Object points to, the value would not be collected, even if nothing else points to the identifier.

Private Names are a specification type here, not directly observable to ECMAScript code. However, in a decorator integration strawman, an object wrapping Private Names would be exposed to allow greater metaprogramming.

Editor's Note
Private fields are deliberately inaccessible outside of the class body. It is proposed that there could be an "escape hatch" to access them though some sort of reflective mechanism; see the GitHub thread. This proposal deliberately omits any such escape hatch.

3.1Notational Conventions

When the phrase newly created object appears in this specification, perfom the following steps on the resulting object obj:

  1. Set obj.[[PrivateFieldValues]] to an empty List.

3.2NewPrivateName ( description )

  1. Return a new unique Private Name value whose [[Description]] value is description.

3.3PrivateFieldFind (P, O)

  1. Assert: P is a Private Name value.
  2. Assert: O is an object with a [[PrivateFieldValues]] internal slot.
  3. For each element entry in O.[[PrivateFieldValues]],
    1. If entry.[[PrivateName]] is P, return entry.
  4. Return empty.

3.4PrivateFieldAdd (P, O, value)

  1. Assert: P is a Private Name value.
  2. If O is not an object, throw a TypeError exception.
  3. Let entry be PrivateFieldFind(P, O).
  4. If entry is not empty, throw a TypeError exception.
  5. Append { [[PrivateName]]: P, [[PrivateFieldValue]]: value } to O.[[PrivateFieldValues]].

3.5PrivateFieldGet (P, O )

  1. Assert: P is a Private Name value.
  2. If O is not an object, throw a TypeError exception.
  3. Let entry be PrivateFieldFind(P, O).
  4. If entry is empty, throw a TypeError exception.
  5. Return entry.[[PrivateFieldValue]].

3.6PrivateFieldSet (P, O, value )

  1. Assert: P is a Private Name value.
  2. If O is not an object, throw a TypeError exception.
  3. Let entry be PrivateFieldFind(P, O).
  4. If entry is empty, throw a TypeError exception.
  5. Set entry.[[PrivateFieldValue]] to value.

3.7Runtime Semantics: Evaluation

MemberExpression:MemberExpression.PrivateName
  1. Let baseReference be the result of evaluating MemberExpression.
  2. Let baseValue be ? GetValue(baseReference).
  3. Let bv be ? RequireObjectCoercible(baseValue).
  4. Let fieldNameString be the StringValue of PrivateName.
  5. Return MakePrivateReference(bv, fieldNameString).
CallExpression:CallExpression.PrivateName
  1. Let baseReference be the result of evaluating CallExpression.
  2. Let baseValue be ? GetValue(baseReference).
  3. Let bv be ? RequireObjectCoercible(baseValue).
  4. Let fieldNameString be the StringValue of PrivateName.
  5. Return MakePrivateReference(bv, fieldNameString).

3.8The Reference Specification Type

Note

The Reference type is used to explain the behaviour of such operators as delete, typeof, the assignment operators, the super keyword and other language features. For example, the left-hand operand of an assignment is expected to produce a reference.

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

A Super Reference is a Reference that is used to represent a name binding that was expressed using the super keyword. A Super Reference has an additional thisValue component and its base value will never be an Environment Record.

The following abstract operations are used in this specification to access the components of references:

  • GetBase(V). Returns the base value component of the reference V.
  • GetReferencedName(V). Returns the referenced name component of the reference V.
  • IsStrictReference(V). Returns the strict reference flag component of the reference V.
  • HasPrimitiveBase(V). Returns true if Type(base) is Boolean, String, Symbol, or Number.
  • IsPropertyReference(V). Returns true if either the base value is an object or HasPrimitiveBase(V) is true; otherwise returns false.
  • IsUnresolvableReference(V). Returns true if the base value is undefined and false otherwise.
  • IsSuperReference(V). Returns true if this reference has a thisValue component.
  • IsPrivateReference(V). Returns the private reference flag component of the reference V.

The following abstract operations are used in this specification to operate on references:

3.8.1GetValue ( V )

  1. ReturnIfAbrupt(V).
  2. If Type(V) is not Reference, return V.
  3. Let base be GetBase(V).
  4. If IsUnresolvableReference(V), throw a ReferenceError exception.
  5. If IsPropertyReference(V), then
    1. If HasPrimitiveBase(V), then
      1. Assert: In this case, base will never be null or undefined.
      2. Let base be ToObject(base).
    2. If IsPrivateReference(V), then
      1. Let env be the running execution context's PrivateNameEnvironment.
      2. Let field be ? ResolveBinding(GetReferencedName(V), env).
      3. Assert: field is a Private Name.
      4. Return ? PrivateFieldGet(field, base).
    3. Return ? base.[[Get]](GetReferencedName(V), GetThisValue(V)).
  6. Else base must be an Environment Record,
    1. Return ? base.GetBindingValue(GetReferencedName(V), IsStrictReference(V)) (see 8.1.1).
Note

The object that may be created in step 5.a.ii is not accessible outside of the above abstract operation and the ordinary object [[Get]] internal method. An implementation might choose to avoid the actual creation of the object.

3.8.2PutValue ( 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), 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 IsPropertyReference(V), then
    1. If HasPrimitiveBase(V) is true, then
      1. Assert: In this case, base will never be null or undefined.
      2. Set base to ToObject(base).
    2. If IsPrivateReference(V), then
      1. Let env be the running execution context's PrivateNameEnvironment.
      2. Let field be ? ResolveBinding(GetReferencedName(V), env).
      3. Assert: field is a Private Name.
      4. Perform ? PrivateFieldSet(field, base, W).
    3. Else,
      1. Let succeeded be ? base.[[Set]](GetReferencedName(V), W, GetThisValue(V)).
      2. If succeeded is false and IsStrictReference(V) is true, throw a TypeError exception.
    4. Return.
  7. Else base must be an Environment Record.
    1. Return ? base.SetMutableBinding(GetReferencedName(V), W, IsStrictReference(V)) (see 8.1.1).
Note

The object that may be created in step 6.a.ii is not accessible outside of the above algorithm and the ordinary object [[Set]] internal method. An implementation might choose to avoid the actual creation of that object.

3.8.3MakePrivateReference ( baseValue, fieldName )

  1. Return a value of type Reference whose base value is baseValue, whose referenced name is fieldName, whose strict reference flag is true, and whose private reference component is true.

3.9Lexically scoped Private Names

Private Names follow typical lexical scoping logic. This section contains amended algorithms for managing the scope of Private Names.

3.9.1Execution Contexts

Table 1: Additional State Components for ECMAScript Code Execution Contexts
Component Purpose
LexicalEnvironment Identifies the Lexical Environment used to resolve identifier references made by code within this execution context.
VariableEnvironment Identifies the Lexical Environment whose EnvironmentRecord holds bindings created by VariableStatements within this execution context.
PrivateNameEnvironment Identifies the Lexical Environment whose EnvironmentRecord holds internal private names created by FieldDefinitions.
Note
The PrivateNameEnvironment Lexical Context is always a chain of Declaration Contexts. Each name begins with "#".
Editor's Note
Private names could have been specified by lumping it all into the LexicalEnvironment. However, this would create false conflicts with object environment records that would need to be resolved. Further, it seems logically cleaner to separate out the distinct namespace into a distinct object.

3.9.2ECMAScript Function Objects

ECMAScript function objects have the additional internal slots listed in Table 2.

Table 2: Internal Slots of ECMAScript Function Objects
Internal Slot Type Description
[[Environment]] Lexical Environment The Lexical Environment that the function was closed over. Used as the outer environment when evaluating the code of the function.
[[PrivateNameEnvironment]] Lexical Environment The Lexical Environment for Private Names that the function was closed over. Used as the outer environment for Private Names when evaluating the code of the function.
[[FormalParameters]] Parse Node The root parse node of the source text that defines the function's formal parameter list.
[[FunctionKind]] String Either "normal", "classConstructor", "generator", or "async".
[[ECMAScriptCode]] Parse Node The root parse node of the source text that defines the function's body.
[[ConstructorKind]] String Either "base" or "derived".
[[Realm]] Realm Record The realm in which the function was created and which provides any intrinsic objects that are accessed when evaluating the function.
[[ScriptOrModule]] Script Record or Module Record The script or module in which the function was created.
[[ThisMode]] (lexical, strict, global) Defines how this references are interpreted within the formal parameters and code body of the function. lexical means that this refers to the this value of a lexically enclosing function. strict means that the this value is used exactly as provided by an invocation of the function. global means that a this value of undefined is interpreted as a reference to the global object.
[[Strict]] Boolean true if this is a strict function, false if this is a non-strict function.
[[HomeObject]] Object If the function uses super, this is the object whose [[GetPrototypeOf]] provides the object where super property lookups begin.
[[Fields]] List of Records as created by ClassFieldDefinitionEvaluation If the function is a class with instancefield declarations, this is a list of records representing those fields and their initializers.

3.9.3FunctionInitialize ( F, kind, ParameterList, Body, Scope, PrivateNameScope )

The abstract operation FunctionInitialize requires the arguments: a function object F, kind which is one of (Normal, Method, Arrow), a parameter list Parse Node specified by ParameterList, a body Parse Node specified by Body, a Lexical Environment specified by Scope, and a Lexical environment PrivateNameScope. FunctionInitialize performs the following steps:

  1. Let len be the ExpectedArgumentCount of ParameterList.
  2. Perform ! SetFunctionLength(F, len).
  3. Let Strict be F.[[Strict]].
  4. Set F.[[Environment]] to Scope.
  5. Set F.[[PrivateNameEnvironment]] to PrivateNameScope.
  6. Set F.[[FormalParameters]] to ParameterList.
  7. Set F.[[ECMAScriptCode]] to Body.
  8. Set F.[[ScriptOrModule]] to GetActiveScriptOrModule().
  9. If kind is Arrow, set F.[[ThisMode]] to lexical.
  10. Else if Strict is true, set F.[[ThisMode]] to strict.
  11. Else, set F.[[ThisMode]] to global.
  12. Return F.

3.9.4FunctionCreate ( kind, ParameterList, Body, Scope, PrivateNameScope, Strict [ , prototype ] )

The abstract operation FunctionCreate requires the arguments: kind which is one of (Normal, Method, Arrow), a parameter list Parse Node specified by ParameterList, a body Parse Node specified by Body, a Lexical Environment specified by Scope, a Lexical Environment specified by PrivateNameScope, a Boolean flag Strict, and optionally, an object prototype. FunctionCreate performs the following steps:

  1. If prototype is not present, then
    1. Set prototype to the intrinsic object %FunctionPrototype%.
  2. If kind is not Normal, let allocKind be "non-constructor".
  3. Else, let allocKind be "normal".
  4. Let F be FunctionAllocate(prototype, Strict, allocKind).
  5. Return FunctionInitialize(F, kind, ParameterList, Body, Scope, PrivateNameScope).

3.9.5GeneratorFunctionCreate ( kind, ParameterList, Body, Scope, PrivateNameScope, Strict )

The abstract operation GeneratorFunctionCreate requires the arguments: kind which is one of (Normal, Method), a parameter list Parse Node specified by ParameterList, a body Parse Node specified by Body, a Lexical Environment specified by Scope, a Lexical Environment specified by PrivateNameScope, and a Boolean flag Strict. GeneratorFunctionCreate performs the following steps:

  1. Let functionPrototype be the intrinsic object %Generator%.
  2. Let F be FunctionAllocate(functionPrototype, Strict, "generator").
  3. Return FunctionInitialize(F, kind, ParameterList, Body, Scope, PrivateNameScope).

3.9.6AsyncGeneratorFunctionCreate (kind, ParameterList, Body, Scope, PrivateNameScope, Strict)

The abstract operation AsyncGeneratorFunctionCreate requires the arguments: kind which is one of (Normal, Method), a parameter list Parse Node specified by ParameterList, a body Parse Node specified by Body, a Lexical Environment specified by Scope, a Lexical Environment specified by PrivateNameScope, and a Boolean flag Strict. AsyncGeneratorFunctionCreate performs the following steps:

  1. Let functionPrototype be the intrinsic object %AsyncGenerator%.
  2. Let F be ! FunctionAllocate(functionPrototype, Strict, "generator").
  3. Return ! FunctionInitialize(F, kind, ParameterList, Body, Scope, PrivateNameScope).

3.9.7AsyncFunctionCreate ( kind, parameters, body, Scope, PrivateNameScope, Strict )

The abstract operation AsyncFunctionCreate requires the arguments: kind which is one of (Normal, Method, Arrow), a parameter list Parse Node specified by parameters, a body Parse Node specified by body, a Lexical Environment specified by Scope, a Lexical Environment specified by PrivateNameScope, and a Boolean flag Strict. AsyncFunctionCreate performs the following steps:

  1. Let functionPrototype be the intrinsic object %AsyncFunctionPrototype%.
  2. Let F be ! FunctionAllocate(functionPrototype, Strict, "async").
  3. Return ! FunctionInitialize(F, kind, parameters, body, Scope, PrivateNameScope).

3.9.8ScriptEvaluation ( scriptRecord )

  1. Let globalEnv be scriptRecord.[[Realm]].[[GlobalEnv]].
  2. Let scriptCxt be a new ECMAScript code execution context.
  3. Set the Function of scriptCxt to null.
  4. Set the Realm of scriptCxt to scriptRecord.[[Realm]].
  5. Set the ScriptOrModule of scriptCxt to scriptRecord.
  6. Set the VariableEnvironment of scriptCxt to globalEnv.
  7. Set the LexicalEnvironment of scriptCxt to globalEnv.
  8. Let privateNameEnv be a new Lexical Environment.
  9. Set the PrivateNameEnvironment of scriptCxt to privateNameEnv.
  10. Suspend the currently running execution context.
  11. Push scriptCxt on to the execution context stack; scriptCxt is now the running execution context.
  12. Let scriptBody be scriptRecord.[[ECMAScriptCode]].
  13. Let result be GlobalDeclarationInstantiation(scriptBody, globalEnv).
  14. If result.[[Type]] is normal, then
    1. Set result to the result of evaluating scriptBody.
  15. If result.[[Type]] is normal and result.[[Value]] is empty, then
    1. Set result to NormalCompletion(undefined).
  16. Suspend scriptCxt and remove it from the execution context stack.
  17. Assert: The execution context stack is not empty.
  18. Resume the context that is now on the top of the execution context stack as the running execution context.
  19. Return Completion(result).

3.9.9PrepareForOrdinaryCall ( F, newTarget )

When the abstract operation PrepareForOrdinaryCall is called with function object F and ECMAScript language value newTarget, the following steps are taken:

  1. Assert: Type(newTarget) is Undefined or Object.
  2. Let callerContext be the running execution context.
  3. Let calleeContext be a new ECMAScript code execution context.
  4. Set the Function of calleeContext to F.
  5. Let calleeRealm be F.[[Realm]].
  6. Set the Realm of calleeContext to calleeRealm.
  7. Set the ScriptOrModule of calleeContext to F.[[ScriptOrModule]].
  8. Let localEnv be NewFunctionEnvironment(F, newTarget).
  9. Set the LexicalEnvironment of calleeContext to localEnv.
  10. Set the VariableEnvironment of calleeContext to localEnv.
  11. Set the PrivateNameEnvironment of calleeContext to F.[[PrivateNameEnvironment]].
  12. If callerContext is not already suspended, suspend callerContext.
  13. Push calleeContext onto the execution context stack; calleeContext is now the running execution context.
  14. NOTE: Any exception objects produced after this point are associated with calleeRealm.
  15. Return calleeContext.

3.9.10Runtime Semantics: InstantiateFunctionObject

With parameters scope and privateNameScope.

FunctionDeclaration:functionBindingIdentifier(FormalParameters){FunctionBody}
  1. If the function code for FunctionDeclaration is strict mode code, let strict be true. Otherwise let strict be false.
  2. Let name be StringValue of BindingIdentifier.
  3. Let F be FunctionCreate(Normal, FormalParameters, FunctionBody, scope, privateNameScope, strict).
  4. Perform MakeConstructor(F).
  5. Perform SetFunctionName(F, name).
  6. Return F.
FunctionDeclaration:function(FormalParameters){FunctionBody}
  1. Let F be FunctionCreate(Normal, FormalParameters, FunctionBody, scope, privateNameScope, true).
  2. Perform MakeConstructor(F).
  3. Perform SetFunctionName(F, "default").
  4. Return F.
Note

An anonymous FunctionDeclaration can only occur as part of an export default declaration, and its function code is therefore always strict mode code.

3.9.11Runtime Semantics: InstantiateFunctionObject

With parameters scope and privateNameScope.

GeneratorDeclaration:function*BindingIdentifier(FormalParameters){GeneratorBody}
  1. If the function code for GeneratorDeclaration is strict mode code, let strict be true. Otherwise let strict be false.
  2. Let name be StringValue of BindingIdentifier.
  3. Let F be GeneratorFunctionCreate(Normal, FormalParameters, GeneratorBody, scope, privateNameScope, strict).
  4. Let prototype be ObjectCreate(%GeneratorPrototype%).
  5. Perform DefinePropertyOrThrow(F, "prototype", PropertyDescriptor{[[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false}).
  6. Perform SetFunctionName(F, name).
  7. Return F.
GeneratorDeclaration:function*(FormalParameters){GeneratorBody}
  1. Let F be GeneratorFunctionCreate(Normal, FormalParameters, GeneratorBody, scope,privateNameScope, true).
  2. Let prototype be ObjectCreate(%GeneratorPrototype%).
  3. Perform DefinePropertyOrThrow(F, "prototype", PropertyDescriptor{[[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false}).
  4. Perform SetFunctionName(F, "default").
  5. Return F.
Note

An anonymous GeneratorDeclaration can only occur as part of an export default declaration, and its function code is therefore always strict mode code.

3.9.12Runtime Semantics: InstantiateFunctionObject

With parameters scope and privateNameScope.

AsyncGeneratorDeclaration:async[no LineTerminator here]function*BindingIdentifier(FormalParameters){AsyncGeneratorBody}
  1. If the function code for AsyncGeneratorDeclaration is strict mode code, let strict be true. Otherwise let strict be false.
  2. Let name be StringValue of BindingIdentifier.
  3. Let F be ! AsyncGeneratorFunctionCreate(Normal, FormalParameters, AsyncGeneratorBody, scope, privateNameScope, strict).
  4. Let prototype be ! ObjectCreate(%AsyncGeneratorPrototype%).
  5. Perform ! DefinePropertyOrThrow(F, "prototype", PropertyDescriptor{[[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false}).
  6. Perform ! SetFunctionName(F, name).
  7. Return F.
AsyncGeneratorDeclaration:async[no LineTerminator here]function*(FormalParameters){AsyncGeneratorBody}
  1. If the function code for AsyncGeneratorDeclaration is strict mode code, let strict be true. Otherwise let strict be false.
  2. Let F be AsyncGeneratorFunctionCreate(Normal, FormalParameters, AsyncGeneratorBody, scope, privateNameScope, strict).
  3. Let prototype be ObjectCreate(%AsyncGeneratorPrototype%).
  4. Perform DefinePropertyOrThrow(F, "prototype", PropertyDescriptor{[[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false}).
  5. Perform SetFunctionName(F, "default").
  6. Return F.
Note

An anonymous AsyncGeneratorDeclaration can only occur as part of an export default declaration.

3.9.13Runtime Semantics: InstantiateFunctionObject

With parameters scope and privateNameScope.

AsyncFunctionDeclaration:async[no LineTerminator here]functionBindingIdentifier(FormalParameters){AsyncFunctionBody}
  1. If the function code for AsyncFunctionDeclaration is strict mode code, let strict be true. Otherwise, let strict be false.
  2. Let name be StringValue of BindingIdentifier.
  3. Let F be ! AsyncFunctionCreate(Normal, FormalParameters, AsyncFunctionBody, scope, privateNameScope, strict).
  4. Perform ! SetFunctionName(F, name).
  5. Return F.
AsyncFunctionDeclaration:async[no LineTerminator here]function(FormalParameters){AsyncFunctionBody}
  1. If the function code for AsyncFunctionDeclaration is strict mode code, let strict be true. Otherwise, let strict be false.
  2. Let F be ! AsyncFunctionCreate(Normal, FormalParameters, AsyncFunctionBody, scope, privateNameScope, strict).
  3. Perform ! SetFunctionName(F, "default").
  4. Return F.

4Automatic Semicolon Insertion

Most ECMAScript statements and declarations must beare logically terminated with a semicolon. Such semicolons may always appear explicitly in the source text. For convenience, however, such semicolons may be omitted from the source text in certain situations. These situations are described by saying that semicolons are automatically inserted into the source code token stream in those situations.

4.1Rules of Automatic Semicolon Insertion

In the following rules, “token” means the actual recognized lexical token determined using the current lexical goal symbol as described in clause 11.

There are three basic rules of semicolon insertion:

  1. When, as the source text is parsed from left to right, a token (called the offending token) is encountered that is not allowed by any production of the grammar, then a semicolon is automatically inserted before the offending token if one or more of the following conditions is true:

    • The offending token is separated from the previous token by at least one LineTerminator.
    • The offending token is }.
    • The previous token is ) and the inserted semicolon would then be parsed as the terminating semicolon of a do-while statement (13.7.2).
  2. When, as the source text is parsed from left to right, the end of the input stream of tokens is encountered and the parser is unable to parse the input token stream as a single instance of the goal nonterminal, then a semicolon is automatically inserted at the end of the input stream.
  3. When, as the source text is parsed from left to right, a token is encountered that is allowed by some production of the grammar, but the production is a restricted production and the token would be the first token for a terminal or nonterminal immediately following the annotation “[no LineTerminator here]” within the restricted production (and therefore such a token is called a restricted token), and the restricted token is separated from the previous token by at least one LineTerminator, then a semicolon is automatically inserted before the restricted token.

However, there is an additional overriding condition on the preceding rules: a semicolon is never inserted automatically if the semicolon would then be parsed as an empty statement or if that semicolon would become one of the two semicolons in the header of a for statement (see 13.7.4).

Note 1

The following are the only restricted productions in the grammar:

UpdateExpression[Yield, Await]:LeftHandSideExpression[?Yield, ?Await][no LineTerminator here]++ LeftHandSideExpression[?Yield, ?Await][no LineTerminator here]-- ContinueStatement[Yield, Await]:continue; continue[no LineTerminator here]LabelIdentifier[?Yield, ?Await]; BreakStatement[Yield, Await]:break; break[no LineTerminator here]LabelIdentifier[?Yield, ?Await]; ReturnStatement[Yield, Await]:return; return[no LineTerminator here]Expression[+In, ?Yield, ?Await]; ThrowStatement[Yield, Await]:throw[no LineTerminator here]Expression[+In, ?Yield, ?Await]; ArrowFunction[In, Yield, Await]:ArrowParameters[?Yield, ?Await][no LineTerminator here]=>ConciseBody[?In] YieldExpression[In, Await]:yield[no LineTerminator here]*AssignmentExpression[?In, +Yield, ?Await] yield[no LineTerminator here]AssignmentExpression[?In, +Yield, ?Await]

The practical effect of these restricted productions is as follows:

  • When a ++ or -- token is encountered where the parser would treat it as a postfix operator, and at least one LineTerminator occurred between the preceding token and the ++ or -- token, then a semicolon is automatically inserted before the ++ or -- token.
  • When a continue, break, return, throw, or yield token is encountered and a LineTerminator is encountered before the next token, a semicolon is automatically inserted after the continue, break, return, throw, or yield token.

The resulting practical advice to ECMAScript programmers is:

  • A postfix ++ or -- operator should appear on the same line as its operand.
  • An Expression in a return or throw statement or an AssignmentExpression in a yield expression should start on the same line as the return, throw, or yield token.
  • A LabelIdentifier in a break or continue statement should be on the same line as the break or continue token.
Note 2
Automatic semicolon insertion applies for all source text, including class bodies. In particular, semicolons may be omitted after class field declarations in certain conditions. Although the same insertion logic described above applies within class bodies, the practicalities of writing class bodies in a semicolon-free style differs between class bodies and other ECMAScript code; see 4.3.2 for some consequences of this property.

4.2Examples of Automatic Semicolon Insertion

This section is non-normative.

The source

{ 1 2 } 3

is not a valid sentence in the ECMAScript grammar, even with the automatic semicolon insertion rules. In contrast, the source

{ 1
2 } 3

is also not a valid ECMAScript sentence, but is transformed by automatic semicolon insertion into the following:

{ 1
;2 ;} 3;

which is a valid ECMAScript sentence.

The source

for (a; b
)

is not a valid ECMAScript sentence and is not altered by automatic semicolon insertion because the semicolon is needed for the header of a for statement. Automatic semicolon insertion never inserts one of the two semicolons in the header of a for statement.

The source

return
a + b

is transformed by automatic semicolon insertion into the following:

return;
a + b;
Note 1

The expression a + b is not treated as a value to be returned by the return statement, because a LineTerminator separates it from the token return.

The source

a = b
++c

is transformed by automatic semicolon insertion into the following:

a = b;
++c;
Note 2

The token ++ is not treated as a postfix operator applying to the variable b, because a LineTerminator occurs between b and ++.

The source

if (a > b)
else c = d

is not a valid ECMAScript sentence and is not altered by automatic semicolon insertion before the else token, even though no production of the grammar applies at that point, because an automatically inserted semicolon would then be parsed as an empty statement.

The source

a = b + c
(d + e).print()

is not transformed by automatic semicolon insertion, because the parenthesized expression that begins the second line can be interpreted as an argument list for a function call:

a = b + c(d + e).print()

In the circumstance that an assignment statement must begin with a left parenthesis, it is a good idea for the programmer to provide an explicit semicolon at the end of the preceding statement rather than to rely on automatic semicolon insertion.

4.3Hazards of Automatic Semicolon Insertion

This section is non-normative.

ECMAScript programs can be written in a style with very few semicolons, based on a heavy dependence on automatic semicolon insertion. However, as described above, semicolons are not inserted at every newline, and some of these cases which do not have an automatically inserted semicolon can be counter-intuitive or confusing.

As new syntactic features are added to ECMAScript, additional cases requiring explicit semicolons emerge over time. As such, consistently explicit semicolon use is recommended.

The term "automatic semicolon insertion hazard" refers, informally, to a place where a developer may expect a semicolon to be inserted, but according to the rules described above, it is not. The rest of this section describes a number of automatic semicolon insertion hazards in this version of ECMAScript.

4.3.1Automatic Semicolon Insertion Hazards in Statement Lists

In a StatementList, many StatementListItems end in semicolons, which may be omitted using automatic semicolon insertion. As a consequence of the rules above, at the end of a line ending an expression, a semicolon will be required if the following line begins with any of the following:

  • An opening parenthesis ((). Without a semicolon, the two lines together will be treated as a function call.
  • An opening square bracket ([). Without a semicolon, the two lines together will be treated as property access, rather than an array literal.
  • A template string (`). Without a semicolon, the two lines together will be interpreted as tagged template literal, with the previous expression as the function tag.
  • Unary + or -. Without a semicolon, the two lines together will be interpreted as a usage of the corresponding infix operator.
  • A RegExp literal. Without a semicolon, the two lines together may be parsed instead as a division, for example if the RegExp has flags.

4.3.2Automatic Semicolon Insertion Hazards in the Top Level of Class Bodies

At the top level of class bodies, the only significant case where semicolons are used is in field declarations. As a consequence of the rules above, at the end of a field declaration with an initializer expression, a semicolon is required if the following line begins with any of the following:

  • A computed property name field or method. Without a semicolon, a field declaration with a computed property name will be treated as a property access; a method with a computed property name would be a Syntax Error.
  • A generator method. A missing semicolon is a Syntax Error.
  • A field named in or instanceof. Without a semicolon, those tokens will instead be interpreted as an operator.

Additionally, the declaration of a field named get, set or static, if it does not have an initializer, is not at the end of the class body, and is not followed by a non-static non-async generator method, requires a semicolon. Without a semicolon, these tokens will be treated as modifiers to the following class element declaration. Note that async does not have this property, as async method declarations do not permit a newline between the async token and the method name.

ACopyright & Software License

Copyright Notice

© 2018 Daniel Ehrenberg, Jeff Morrison, Kevin Smith, Kevin Gibbons

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 https://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.