Stage 1 Draft / January 7, 2017

Private Fields

1Introduction

This proposal adds syntactic support for per-instance private object state by means of private field declarations within class bodies.

See the proposal repository for background material and discussion.

class Point { #x; #y; constructor(x = 0, y = 0) { #x = +x; #y = +y; } get x() { return #x } set x(value) { #x = +value } get y() { return #y } set y(value) { #y = +value } equals(p) { return #x === p.#x && #y === p.#y } toString() { return `Point<${ #x },${ #y }>` } }

2Private Field Definitions

Syntax

PrivateName::#IdentifierName ClassElement[Yield]:MethodDefinition[?Yield] staticMethodDefinition[?Yield] PrivateFieldDefinition[?Yield] ; PrivateFieldDefinition[Yield]:PrivateNameInitializer[In, ?Yield]opt; It is proposed that private field declarations may begin with an additional private or pri keyword; see the GitHub thread. Another proposed addition is an abbreviated comma syntax, of the form pri x, y.

2.1Static Semantics: PrivateStringValue

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.2Static Semantics: Early Errors

ClassBody:ClassElementList

2.3Static Semantics: PrivateBoundNames

PrivateFieldDefinition:PrivateNameInitializeropt;
  1. Return a new List containing the PrivateStringValue of PrivateName.
ClassElement:MethodDefinition ClassElement:staticMethodDefinition ClassElement:;
  1. Return a new empty List.
ClassElement:PrivateFieldDefinition
  1. Return PrivateBoundNames of PrivateFieldDefinition.
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.4Static Semantics: IsStatic

ClassElement:PrivateFieldDefinition
  1. Return false.

2.5Static Semantics: PropName

ClassElement:PrivateFieldDefinition
  1. Return empty.

2.6Static Semantics: NonConstructorMethodDefinitions

ClassElementList:ClassElement
  1. If ClassElement is the production ClassElement:; , return a new empty List.
  2. If ClassElement is the production ClassElement:PrivateFieldDefinition , return a new empty List.
  3. If IsStatic of ClassElement is false and PropName of ClassElement is "constructor", return a new empty List.
  4. Return a List containing ClassElement.

2.7Static Semantics: PrivateFieldDefinitions

ClassElementList:ClassElement
  1. If ClassElement is the production ClassElement:PrivateFieldDefinition , return a List containing ClassElement.
  2. Else, return a new empty List.
ClassElementList:ClassElementListClassElement
  1. Let list be PrivateFieldDefinitions of ClassElementList.
  2. If ClassElement is the production ClassElement:PrivateFieldDefinition , append ClassElement to the end of list.
  3. Return list.

2.8Runtime Semantics: PrivateFieldDefinitionEvaluation

With parameter homeObject.

PrivateFieldDefinition:PrivateNameInitializer[In, ?Yield]opt;
  1. Let bindingName be PrivateStringValue of PrivateName.
  2. Let field be NewPrivateField();
  3. Let scope be the running execution context's PrivateFieldEnvironment.
  4. Let scopeEnvRec be scope's EnvironmentRecord.
  5. Perform ! scopeEnvRec.InitializeBinding(bindingName, field).
  6. NOTE: Since bindingName is not a valid Identifier, field is not visible to user code.
  7. If Initializeropt is present,
    1. Let lex be the Lexical Environment of the running execution context.
    2. Let initializer be FunctionCreate(Method, empty, Initializeropt, lex, true).
    3. Perform MakeMethod(initializer, homeObject);
  8. Else, let initializer be empty.
  9. Return Record{[[PrivateFieldDefinitionIdentifier]]: field, [[PrivateFieldDefinitionInitializer]]: initializer}.
The scope that the initializer is evaluated in is equivalent to a method which is called with no arguments.

2.9Runtime Semantics: EvaluateBody

With parameter functionObject.

Initializer[In, Yield]:=AssignmentExpression[?In, ?Yield]
  1. Return the result of evaluating AssignmentExpression.

2.10Runtime 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 PrivateFieldEnvironment 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. Set the running execution context's PrivateFieldEnvironment to classPrivateEnvironment.
    3. Let superclass be the result of evaluating ClassHeritage.
    4. Set the running execution context's PrivateFieldEnvironment to outerPrivateEnvironment.
    5. Set the running execution context's LexicalEnvironment to lex.
    6. ReturnIfAbrupt(superclass).
    7. If superclass is null, then
      1. Let protoParent be null.
      2. Let constructorParent be the intrinsic object %FunctionPrototype%.
    8. Else if IsConstructor(superclass) is false, throw a TypeError exception.
    9. 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, 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.
    2. Else,
      1. Let constructor be the result of parsing the source text
        constructor( ){ }
        using the syntactic grammar with the goal symbol MethodDefinition.
  15. Set the running execution context's LexicalEnvironment to classScope.
  16. Set the running execution context's PrivateFieldEnvironment 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, set F's [[ConstructorKind]] internal slot 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 methods be a new empty List.
  25. Else, let methods be NonConstructorMethodDefinitions of ClassBody.
  26. For each ClassElement m in order from methods,
    1. If IsStatic of m is false, then
      1. Let status be the result of performing PropertyDefinitionEvaluation for m with arguments proto and false.
    2. Else,
      1. Let status be the result of performing PropertyDefinitionEvaluation for m with arguments F and false.
    3. If status is an abrupt completion, then
      1. Set the running execution context's PrivateFieldEnvironment to outerPrivateEnvironment.
      2. Set the running execution context's LexicalEnvironment to lex.
      3. Return Completion(status).
  27. If ClassBodyopt is not present, let fieldDefinitions be a new empty List.
  28. Else, let fieldDefinitions be PrivateFieldDefinitions of ClassBody.
  29. Let privateFields be a new empty List.
  30. For each ClassElement f in order from fieldDefinitions,
    1. Let fieldRecord be the result of performing PrivateFieldDefinitionEvaluation for f with argument proto.
    2. Append fieldRecord to privateFields.
  31. Set the value of F's [[PrivateFieldDefinitions]] internal slot to privateFields.
  32. Set the running execution context's PrivateFieldEnvironment to outerPrivateEnvironment.
  33. Set the running execution context's LexicalEnvironment to lex.
  34. If className is not undefined, then
    1. Perform classScopeEnvRec.InitializeBinding(className, F).
  35. Return F.
Each time a class declaration executes, distinct internal Private Field Identifiers 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.

3Allocation and Initialization

3.1InitializePrivateFields ( O, constructor )

  1. Assert: Type(O) is Object.
  2. Assert: constructor is an ECMAScript function object.
  3. Let fieldRecords be the value of constructor's [[PrivateFieldDefinitions]] internal slot.
  4. For each element fieldRecord of fieldRecords,
    1. Let initializer be fieldRecord.[[PrivateFieldDefinitionInitializer]].
    2. If initializer is not empty, then
      1. Let initValue be ? Call(initializer, O).
    3. Else,
      1. Let initialValue be undefined
    4. Perform ? PrivateFieldAdd(fieldRecord.[[PrivateFieldDefinitionIdentifier]], O, initialValue).
  5. Set the running execution context's LexicalEnvironment to lex.
  6. Return.
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. When integrating this specification with public fields, ensure that the field additions are interspersed in definition order in how they are added to the reciever.

3.2[[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's [[ConstructorKind]] internal slot.
  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 InitializePrivateFields(thisArgument, F).
    3. If result is an abrupt completion, then
      1. Remove calleeContext from the 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().
Private 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.

3.3The super Keyword

3.3.1Runtime Semantics: Evaluation

Note

This algorithm has been modified to inline the abstract operation GetSuperConstructor.

SuperCall:superArguments
  1. Let newTarget be GetNewTarget().
  2. If newTarget is undefined, throw a ReferenceError exception.
  3. Let thisER be GetThisEnvironment().
  4. Assert: thisER is a function Environment Record.
  5. Let F be thisER.[[FunctionObject]].
  6. Assert: F is an ECMAScript function object.
  7. Let superConstructor be ? F.[[GetPrototypeOf]]().
  8. If IsConstructor(superConstructor) is false, throw a TypeError exception.
  9. Let argList be ArgumentListEvaluation of Arguments.
  10. ReturnIfAbrupt(argList).
  11. Let thisValue be ? Construct(superConstructor, argList, newTarget).
  12. Perform ? thisER.BindThisValue(thisValue).
  13. Perform ? InitializePrivateFields(thisValue, F).
  14. Return thisValue.
Private fields are added to whatever value is returned by the super constructor. These semantics allow private fields to be used in exotic situations like custom elements upgrade.

4Private References

Syntax

MemberExpression[Yield]:MemberExpression[?Yield].PrivateName PrimaryExpression[Yield]:PrivateName This proposal allows both abbreviated references to private state (#x) which have an implicit this as the receiver, as well as explicit receivers (obj.#x). The implicit receiver form is intended for better ergonomics for the common case, and the explicit receiver form allows the full generality of "class-private" (as opposed to "instance-private").

4.1Runtime 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 PrivateStringValue of PrivateName.
  5. Return MakePrivateReference(bv, fieldNameString).
PrimaryExpression:PrivateName
  1. Let baseValue be ? ResolveThisBinding().
  2. Let bv be ? RequireObjectCoercible(baseValue).
  3. Let fieldNameString be the PrivateStringValue of PrivateName.
  4. Return MakePrivateReference(bv, fieldNameString).

4.2The delete Operator

4.2.1Static Semantics: Early Errors

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.

Private fields may not be deleted

4.2.2Runtime 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.

4.3The 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:

4.3.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 PrivateFieldEnvironment.
      2. Let field be ? ResolveBinding(GetReferencedName(V), env).
      3. Assert: field is a Private Field Identifier.
      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.

4.3.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 PrivateFieldEnvironment.
      2. Let field be ? ResolveBinding(GetReferencedName(V), env).
      3. Assert: field is a Private Field Identifier.
      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.

4.3.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.

4.4Execution 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.
PrivateFieldEnvironment Identifies the Lexical Environment whose EnvironmentRecord holds internal private field identifiers created by PrivateFieldDefinitions.
Note
The PrivateFieldEnvironment Lexical Context is always a chain of Declaration Contexts. Each name begins with "#".
Private fields identifiers could be 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. When a new execution context is created for an ECMAScript code execution context, the PrivateFieldIdentifiers value is inherited from the running execution context, or if none exists, a new Declaration Context with a null parent. Elaborate the preceding paragraph with spec text inserted in each relevant place

4.5Early errors for referring to undefined private names

4.5.1Static Semantics: AllPrivateNamesValid

AllPrivateNamesValid is an abstract operation which takes names as an argument. MemberExpression[Yield]:MemberExpression[?Yield].PrivateName PrimaryExpression[Yield]:PrivateName
  1. If PrivateStringValue 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. Elaborate the preceding paragraph with spec text inserted in each relevant place

4.5.2Static Semantics: Early Errors

Script:ScriptBodyopt
  1. Let names be an empty List.
  2. If Script is parsed directly from PerformEval,
    1. Let env be the running execution context's PrivateFieldEnvironment.
    2. Repeat while env is not null,
      1. For each binding named N in env,
        1. If names does not contain N, append N to names.
      2. Let env be env's outer environment reference.
  3. If AllPrivateNamesValid of ScriptBody with the argument names is false, throw a SyntaxError.
Module:ModuleBodyopt
References to PrivateNames which are not lexically present cause an early error. PrivateNames with or without an explicit receiver are treated identically, see bug thread where a stricter policy was proposed and rejected.

5Private Field Identifiers

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

All ECMAScript objects have a new additional internal slot, [[PrivateFieldValues]], which is a List of Records of the form { [[PrivateFieldIdentifer]]: Private Field Identifier, [[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.

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, PrivateFieldIdentifiers 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 Field Identifiers are a specification type here, not directly observable to ECMAScript code. However, in a decorator integration strawman, an object wrapping Private Field Identifiers would be exposed to allow greater metaprogramming.

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 proposa deliberately omits any such escape hatch.

5.1ObjectCreate (proto [ , internalSlotsList ])

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

  1. If internalSlotsList was not provided, let internalSlotsList be a new empty List.
  2. Let obj be a newly created object with an internal slot for each name in internalSlotsList.
  3. Set obj's essential internal methods to the default ordinary object definitions specified in 9.1.
  4. Set obj.[[Prototype]] to proto.
  5. Set obj.[[Extensible]] to true.
  6. Set obj.[[PrivateFieldValues]] to an empty List.
  7. Return obj.
All ECMAScript objects, including Proxies, and any user exotic object, should have a [[PrivateFieldValues]] internal slot iniitlaized to an empty List.

5.2NewPrivateField ()

  1. Return a new globally unique Private Field Identifier value.

5.3PrivateFieldFind (P, O)

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

5.4PrivateFieldAdd (P, O, value)

  1. Assert: P is a Private Field Identifier 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 { [[PrivateFieldIdentifier]]: P, [[PrivateFieldValue]]: value } to O.[[PrivateFieldValues]].

5.5PrivateFieldGet (P, O )

  1. Assert: P is a Private Field Identifier 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]].

5.6PrivateFieldSet (P, O, value )

  1. Assert: P is a Private Field Identifier 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.