├── .gitignore ├── package.json ├── spec ├── introduction.htm ├── index.htm ├── new-productions.htm └── modified-productions.htm ├── update_ghpages.sh └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.tmp 2 | *.swp 3 | node_modules 4 | ecmarkup.js 5 | ecmarkup.css 6 | index.htm 7 | .DS_* 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "es-class-public-fields", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "ecmarkup": "^3.2.6" 6 | }, 7 | "scripts": { 8 | "generate": "ecmarkup spec/index.htm index.htm --css ecmarkup.css --js ecmarkup.js", 9 | "watch": "ecmarkup --watch spec/index.htm index.htm --css ecmarkup.css --js ecmarkup.js" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /spec/introduction.htm: -------------------------------------------------------------------------------- 1 |

Introduction

2 | 3 |

Today ES classes are currently limited to declarative specification of 4 | methods, but declarative specification of fields is left to ad-hoc expando 5 | mutations on class instances in various places.

6 | 7 |

This proposal aims to provide a declarative mechanism for specifying fields 8 | intended to be placed on classes. Such a mechanism is useful for both developers 9 | and tooling alike as it provides a place to specify the intended properties.

10 | -------------------------------------------------------------------------------- /update_ghpages.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -x 3 | set -o errexit 4 | set -v 5 | 6 | #node node_modules/.bin/ecmarkup \ 7 | # spec/index.htm index.htm.tmp \ 8 | # --css ecmarkup.css.tmp \ 9 | # --js ecmarkup.js.tmp 10 | npm run generate 11 | mv index.htm index.htm.tmp 12 | mv ecmarkup.css ecmarkup.css.tmp 13 | mv ecmarkup.js ecmarkup.js.tmp 14 | 15 | git checkout gh-pages 16 | mv index.htm.tmp index.htm 17 | mv ecmarkup.css.tmp ecmarkup.css 18 | mv ecmarkup.js.tmp ecmarkup.js 19 | git commit -a -m 'update gh-pages' 20 | -------------------------------------------------------------------------------- /spec/index.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
 7 | title: Public Class Fields
 8 | stage: 2
 9 | contributors: Jeff Morrison
10 | 
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NOTE: This proposal has been merged with the [Private Fields proposal](https://github.com/tc39/proposal-private-fields) to form a single unified proposal [here](https://github.com/tc39/proposal-class-fields). 2 | 3 | Please do not create new issues/PRs on this repo. 4 | 5 | # ES Class Fields & Static Properties 6 | 7 | This presents two related proposals: "class instance fields" and "class static fields". "Class instance fields" describe properties intended to exist on instances of a class (and may optionally include initializer expressions for said properties). "Class static fields" are declarative properties that exist on the class object itself (and may optionally include initializer expressions for said properties). 8 | 9 | Latest spec text: https://tc39.github.io/proposal-class-public-fields/ 10 | -------------------------------------------------------------------------------- /spec/new-productions.htm: -------------------------------------------------------------------------------- 1 |

New Productions

2 | 3 | 4 |

|PublicFieldDefinition|

5 | 6 | 7 | PublicFieldDefinition : 8 | PropertyName[?Yield] Initializer? ; 9 | 10 | 11 | 12 |

Static Semantics: Early Errors

13 | 14 | 15 | PublicFieldDefinition : 16 | PropertyName[?Yield] Initializer? 17 | 18 | 21 |
22 |
23 | 24 | 25 |

Static Semantics: PropName

26 | 27 | 28 | PublicFieldDefinition : PropertyName Initializer? 29 | 30 | 31 | 1. Return PropName of |PropertyName|. 32 | 33 |
34 | 35 | 36 |

Static Semantics: ClassPublicFields

37 | 38 | ClassElementList: ClassElement 39 | 40 | 1. If |ClassElement| is the production 41 | ClassElement : PublicFieldDefinition, return 42 | a List containing |ClassElement|. 43 | 1. If |ClassElement| is the production 44 | ClassElement : static PublicFieldDefinition, 45 | return a List containing |ClassElement|. 46 | 1. Return a new empty List. 47 | 48 | 49 | ClassElementList: ClassElementList ClassElement 50 | 51 | 1. Let _list_ be ClassPublicFields of |ClassElementList|. 52 | 1. If |ClassElement| is the production 53 | ClassElement : PublicFieldDefinition, append 54 | |ClassElement| to the end of _list_. 55 | 1. If |ClassElement| is the production 56 | ClassElement : static PublicFieldDefinition, 57 | append |ClassElement| to the end of _list_. 58 | 1. Return _list_. 59 | 60 |
61 | 62 | 63 |

ClassPublicFieldDefinitionEvaluation

64 | 65 |

With parameters _isStatic_ and _homeObject_.

66 | 67 | 68 | PublicFieldDefinition : PropertyName[?Yield] Initializer? ; 69 | 70 | 71 | 1. Let _fieldName_ be the result of performing PropName of |PropertyName|. 72 | 1. If |Initializer_opt| is present, 73 | 1. Let _lex_ be the Lexical Environment of the running execution context. 74 | 1. Let _initializer_ be FunctionCreate(~Method~, ~empty~, |Initializer_opt|, _lex_, *true*). 75 | 1. Perform MakeMethod(_initializer_, _homeObject_). 76 | 1. Else, let _initializer_ be ~empty~. 77 | 1. Return Record{ 78 | [[name]]: _fieldName_, 79 | [[initializer]]: _initializer_, 80 | [[static]]: _isStatic_, 81 | }. 82 | 83 |
84 | 85 | 86 |

Runtime Semantics: EvaluateBody

87 | 88 |

With parameter _functionObject_.

89 | 90 | 91 | Initializer[In, Yield] : 92 | `=` AssignmentExpression[?In, ?Yield] 93 | 94 | 95 | 1. Return the result of evaluating |AssignmentExpression|. 96 | 97 |
98 | 99 | 100 |

InitializePublicStaticFields(_F_)

101 | 102 | 103 | 1. Assert: Type(_F_) is Object. 104 | 1. Assert: _F_ is an ECMAScript function object. 105 | 1. Let _publicFieldRecords_ be the value of _F_'s [[PublicFields]] internal slot. 106 | 1. For each item _fieldRecord_ in order from _publicFieldRecords_, 107 | 1. If _fieldRecord_.[[static]] is *true*, then 108 | 1. Let _fieldName_ be _fieldRecord_.[[name]]. 109 | 1. Let _initializer_ be _fieldRecord_.[[initializer]]. 110 | 1. If _initializer_ is not ~empty~, then 111 | 1. Let _initValue_ be ? Call(_initializer_, *undefined*). 112 | 1. Else, let _initValue_ be *undefined*. 113 | 1. Let _desc_ be PropertyDescriptor { 114 | [[configurable]]: *false*, 115 | [[enumerable]]: *true*, 116 | [[writable]]: *true*, 117 | [[value]]: _initValue_ 118 | }. 119 | 1. Perform ?DefinePropertyOrThrow (_F_, _fieldName_, _desc_). 120 | 1. Return. 121 | 122 |
123 | 124 | 125 |

InitializePublicInstanceFields ( _O_, _constructor_ )

126 | 127 |

128 | TODO: Factor out the lexical environment wrangling and do that at the 129 | callsites of this procedure. 130 |

131 | 132 | We likely want to execute public and private fields their coalesced order of 133 | definition, so when the two proposals merge we'll probably want to merge 134 | their initialization procedures as well. 135 | 136 | 137 | 138 | 1. Assert: Type ( _O_ ) is Object. 139 | 1. Assert: Assert _constructor_ is an ECMAScript function object. 140 | 1. Let _publicFieldRecords_ be the value of _constructor_'s [[PublicFields]] internal slot. 141 | 1. For each item _fieldRecord_ in order from _publicFieldRecords_, 142 | 1. If _fieldRecord_.[[static]] is *false*, then 143 | 1. Let _fieldName_ be _fieldRecord_.[[name]] 144 | 1. Let _initializer_ be _fieldRecord_.[[initializer]]. 145 | 1. If _initializer_ is not ~empty~, then 146 | 1. Let _initValue_ be ? Call(_initializer_, _O_). 147 | 1. Else, 148 | 1. Let _initValue_ be ~undefined~. 149 | 1. Let _desc_ be PropertyDescriptor { 150 | [[configurable]]: *false*, 151 | [[enumerable]]: *true*, 152 | [[writable]]: *true*, 153 | [[value]]: _initValue_ 154 | } 155 | 1. Perform ? DefinePropertyOrThrow (_O_, _fieldName_, _desc_) 156 | 1. Set the running execution context's LexicalEnvironment to _lex_. 157 | 1. Return. 158 | 159 |
160 | -------------------------------------------------------------------------------- /spec/modified-productions.htm: -------------------------------------------------------------------------------- 1 |

Modified Productions

2 | 3 | 4 |

Class Definitions

5 | 6 | 7 |

Static Semantics: Early Errors

8 | ClassTail : ClassHeritage? `{` ClassBody `}` 9 | 19 | ClassBody : ClassElementList 20 | 25 | ClassElement : MethodDefinition 26 | 34 | ClassElement : `static` MethodDefinition 35 | 43 | 44 | ClassElement : `static` PublicFieldDefinition 45 |
    46 |
  • 47 | It is a Syntax Error if PropName of |PublicFieldDefinition| is `"prototype"`. 48 |
  • 49 |
50 |
51 |
52 | 53 | 54 |

Static Semantics: IsStatic

55 | 56 | 57 | ClassElement : PublicFieldDefinition 58 | 59 | 1. Return *false*. 60 | 61 | 62 | ClassElement : static PublicFieldDefinition 63 | 64 | 1. Return *true*. 65 | 66 | 67 |
68 | 69 | 70 |

|ClassElement|

71 | 72 | 73 | MethodDefinition 74 | static MethodDefinition 75 | 76 | PublicFieldDefinition 77 | static PublicFieldDefinition 78 | 79 | ; 80 | 81 |
82 | 83 | 84 |

Runtime Semantics: ClassDefinitionEvaluation

85 | 86 |

With parameter _className_.

87 | ClassTail : ClassHeritage? `{` ClassBody? `}` 88 | 89 | 1. Let _lex_ be the LexicalEnvironment of the running execution context. 90 | 1. Let _classScope_ be NewDeclarativeEnvironment(_lex_). 91 | 1. Let _classScopeEnvRec_ be _classScope_'s EnvironmentRecord. 92 | 1. If _className_ is not *undefined*, then 93 | 1. Perform _classScopeEnvRec_.CreateImmutableBinding(_className_, *true*). 94 | 1. If |ClassHeritage_opt| is not present, then 95 | 1. Let _protoParent_ be the intrinsic object %ObjectPrototype%. 96 | 1. Let _constructorParent_ be the intrinsic object %FunctionPrototype%. 97 | 1. Else, 98 | 1. Set the running execution context's LexicalEnvironment to _classScope_. 99 | 1. Let _superclass_ be the result of evaluating |ClassHeritage|. 100 | 1. Set the running execution context's LexicalEnvironment to _lex_. 101 | 1. ReturnIfAbrupt(_superclass_). 102 | 1. If _superclass_ is *null*, then 103 | 1. Let _protoParent_ be *null*. 104 | 1. Let _constructorParent_ be the intrinsic object %FunctionPrototype%. 105 | 1. Else if IsConstructor(_superclass_) is *false*, throw a *TypeError* exception. 106 | 1. Else, 107 | 1. Let _protoParent_ be ? Get(_superclass_, `"prototype"`). 108 | 1. If Type(_protoParent_) is neither Object nor Null, throw a *TypeError* exception. 109 | 1. Let _constructorParent_ be _superclass_. 110 | 1. Let _proto_ be ObjectCreate(_protoParent_). 111 | 1. If |ClassBody_opt| is not present, let _constructor_ be ~empty~. 112 | 1. Else, let _constructor_ be ConstructorMethod of |ClassBody|. 113 | 1. If _constructor_ is ~empty~, then 114 | 1. If |ClassHeritage_opt| is present and _protoParent_ is not *null*, then 115 | 1. Let _constructor_ be the result of parsing the source text 116 |
constructor(... args){ super (...args);}
117 | using the syntactic grammar with the goal symbol |MethodDefinition[~Yield]|. 118 | 1. Else, 119 | 1. Let _constructor_ be the result of parsing the source text 120 |
constructor( ){ }
121 | using the syntactic grammar with the goal symbol |MethodDefinition[~Yield]|. 122 | 1. Set the running execution context's LexicalEnvironment to _classScope_. 123 | 1. Let _constructorInfo_ be the result of performing DefineMethod for _constructor_ with arguments _proto_ and _constructorParent_ as the optional _functionPrototype_ argument. 124 | 1. Assert: _constructorInfo_ is not an abrupt completion. 125 | 1. Let _F_ be _constructorInfo_.[[Closure]]. 126 | 1. If |ClassHeritage_opt| is present and _protoParent_ is not *null*, then set _F_.[[ConstructorKind]] to `"derived"`. 127 | 1. Perform MakeConstructor(_F_, *false*, _proto_). 128 | 1. Perform MakeClassConstructor(_F_). 129 | 1. Perform CreateMethodProperty(_proto_, `"constructor"`, _F_). 130 | 1. If |ClassBody_opt| is not present, let _methods_ be a new empty List. 131 | 1. Else, let _methods_ be NonConstructorMethodDefinitions of |ClassBody|. 132 | 1. For each |ClassElement| _m_ in order from _methods_ 133 | 1. If IsStatic of _m_ is *false*, then 134 | 1. Let _status_ be the result of performing PropertyDefinitionEvaluation for _m_ with arguments _proto_ and *false*. 135 | 1. Else, 136 | 1. Let _status_ be the result of performing PropertyDefinitionEvaluation for _m_ with arguments _F_ and *false*. 137 | 1. If _status_ is an abrupt completion, then 138 | 1. Set the running execution context's LexicalEnvironment to _lex_. 139 | 1. Return Completion(_status_). 140 | 1. Set the running execution context's LexicalEnvironment to _lex_. 141 | 1. If _className_ is not *undefined*, then 142 | 1. Perform _classScopeEnvRec_.InitializeBinding(_className_, _F_). 143 | 1. If |ClassBody_opt| is not present, let _publicFields_ be a new empty List. 144 | 1. Else, let _publicFields_ be the result of performing 145 | ClassPublicFields of |ClassBody|. 146 | 1. Let _publicFieldRecords_ be a new empty List. 147 | 1. For each item _publicField_ in order from _publicFields_, 148 | 1. Let _isStatic_ be the result of performing IsStatic of _publicField_. 149 | 1. If _isStatic_, let _homeObject_ be _F_, otherwise let _homeObject_ be _proto_. 150 | 1. Let _fieldRecord_ be the result of performing 151 | ClassPublicFieldDefinitionEvaluation for _publicField_ with arguments 152 | _isStatic_ and _homeObject_. 153 | 1. Append _fieldRecord_ to _publicFieldRecords_. 154 | 1. Set the value of _F_'s [[PublicFields]] internal slot to _publicFieldRecords_. 155 | 1. Set the running execution context's LexicalEnvironment to _classScope_. 156 | 1. Let _result_ be InitializePublicStaticFields(_F_). 157 | 1. If _result_ is an abrupt completion, then 158 | 1. Set the running execution context's LexicalEnvironment to _lex_. 159 | 1. Return Completion(_result_) 160 | 1. Set the running execution context's LexicalEnvironment to _lex_. 161 | 1. Return _F_. 162 |
163 |
164 |
165 | 166 | 167 |

[[Construct]] ( _argumentsList_, _newTarget_)

168 |

169 | The [[Construct]] internal method for an ECMAScript Function object _F_ is 170 | called with parameters _argumentsList_ and _newTarget_. _argumentsList_ is 171 | a possibly empty List of ECMAScript language values. The following steps are 172 | taken: 173 |

174 | 175 | 1. Assert: _F_ is an ECMAScript function object. 176 | 1. Assert: Type(_newTarget_) is Object. 177 | 1. Let _callerContext_ be the running execution context. 178 | 1. Let _kind_ be _F_.[[ConstructorKind]]. 179 | 1. If _kind_ is `"base"`, then 180 | 1. Let _thisArgument_ be ? OrdinaryCreateFromConstructor(_newTarget_, `"%ObjectPrototype%"`). 181 | 1. Let _calleeContext_ be PrepareForOrdinaryCall(_F_, _newTarget_). 182 | 1. Assert: _calleeContext_ is now the running execution context. 183 | 1. If _kind_ is `"base"`, then 184 | 1. Perform OrdinaryCallBindThis(_F_, _calleeContext_, _thisArgument_). 185 | 1. Let _result_ be InitializePublicInstanceFields(_thisArgument_, _F_). 186 | 1. If _result_ is an abrupt completion, then 187 | 1. Remove _calleeContext_ from execution context stack and restore 188 | _callerContext_ as the running execution context. 189 | 1. Return Completion(_result_). 190 | 1. Let _constructorEnv_ be the LexicalEnvironment of _calleeContext_. 191 | 1. Let _envRec_ be _constructorEnv_'s EnvironmentRecord. 192 | 1. Let _result_ be OrdinaryCallEvaluateBody(_F_, _argumentsList_). 193 | 1. Remove _calleeContext_ from the execution context stack and restore _callerContext_ as the running execution context. 194 | 1. If _result_.[[Type]] is ~return~, then 195 | 1. If Type(_result_.[[Value]]) is Object, return NormalCompletion(_result_.[[Value]]). 196 | 1. If _kind_ is `"base"`, return NormalCompletion(_thisArgument_). 197 | 1. If _result_.[[Value]] is not *undefined*, throw a *TypeError* exception. 198 | 1. Else, ReturnIfAbrupt(_result_). 199 | 1. Return ? _envRec_.GetThisBinding(). 200 | 201 |
202 | 203 | 204 |

The `super` Keyword

205 | 206 | 207 |

Runtime Semantics: Evaluation

208 | SuperCall : `super` Arguments 209 | 210 | 1. Let _newTarget_ be GetNewTarget(). 211 | 1. If _newTarget_ is *undefined*, throw a *ReferenceError* exception. 212 | 1. Let _func_ be ? GetSuperConstructor(). 213 | 1. Let _argList_ be ArgumentListEvaluation of |Arguments|. 214 | 1. ReturnIfAbrupt(_argList_). 215 | 1. Let _result_ be ? Construct(_func_, _argList_, _newTarget_). 216 | 1. Let _thisER_ be GetThisEnvironment( ). 217 | 1. Perform ? InitializePublicInstanceFields(_thisValue_, _F_). 218 | 1. Return ? _thisER_.BindThisValue(_result_). 219 | 220 |
221 |
222 | 223 | 224 |

Runtime Semantics: PerformEval ( _x_, _evalRealm_, _strictCaller_, _direct_ )

225 | 226 |

Additional Early Error Rules for Eval Inside |Initializer|

227 |

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

228 | ScriptBody : StatementList 229 | 233 |
234 |
235 | --------------------------------------------------------------------------------