-
-
Notifications
You must be signed in to change notification settings - Fork 5.8k
Description
Static Class Features: Stage 3
Advance Static Class Features for Stage 3 (Shu-yu Guo @syg) (Daniel Ehrenberg @littledan)
Proposal co-written with @tim-mc and @robpalme. We also intend to follow up and implement it with @rpamely, @tim-mc, @mkubilayk .
Info
Proposed at TC39 Meeting: May 2018
Slides at the meeting: https://docs.google.com/presentation/d/1YzFr7EIGiX2YagfFMjkI-lVR6ouoRfPbTNLY--NGbC4/edit?usp=sharing
Proposal Repo: https://github.com/tc39/proposal-static-class-features/
Complete article on the subject by Shu-yu Guo: https://rfrn.org/%7Eshu/2018/05/02/the-semantics-of-all-js-class-elements.html
Babel contribution recommended by @jridgewell to @robpalme
The work to be done towards Stage 3 will be added in plugin-proposal-class-properties.
Examples
Static Public Fields
class Account {
static routingNumber = 1017;
get transactionIdPrefix() {
return `${Account.routingNumber}-${this.uuid}`;
}
}Static Public Methods
class Account {
static convertToEuro(dollars) {
return util.USDToEuro(dollars);
}
get euroConversionDisplayAmt () {
return `Current Balance (EUR): ${Account.convertToEuro(this.accountBalance)}`
}Static private fields
class Account {
static #transactions = [];
static get nbTransactions() {
return Account.#transactions.length;
}
getDollars() {
return Account.#transactions.reduce(/* ... */);
}
}Static private methods
class Account {
// ...
static #makeTransaction(dollars, from, to) {
Account.#transactions = this.#transactions.concat(/* ... */);
}
transfer(dollars, targetAccount) {
return Account.#makeTransaction(dollars, this, targetAccount);
}
}Basic Rules
- Check that the
<Class Name>.#<static private field/method>notation is within the lexical scope of<Class Name>- Checked during transform - Check that the
this.#<static private field/method>has a provenance of<Class Name>- See Subclassing Hazard in the slides (around slide 13) - Checked at runtime
ESTree/Parsing
- For the
statickeyword, we use the existing parser - For the
#character, we use (or enhance) the existing parser (thanks to the work done in Class private properties #7842 - Class private properties)
Transform
Public
- Public static fields/methods will be added to the
<Class Name>object - Accessors will be added using
Object.assign
Private
- Transform to use helper functions similar to private instance fields:
classStaticPrivateFieldGetandclassStaticPrivateFieldSet - Add an in-closure
_<static private fields/method>variable outside of the class that will be manipulated by the helper functions - Here is a potential output of the two last examples put together, in order to explain how to achieve privacy:
var Account =
/*#__PURE__*/
function () {
"use strict";
function Account() {}
babelHelpers.createClass(Account, [{
key: "transfer",
value: function transfer(dollars, targetAccount) {
babelHelpers.classStaticPrivateFieldGet(Account, _makeTransaction)(dollars, targetAccount);
}
}, {
key: "getDollars",
value: function getDollars() {
babelHelpers.classStaticPrivateFieldGet(Account, _transactions).reduce(/* ... */);
}
}]);
Object.assign(Account, {
get nbTransactions() {
return babelHelpers.classStaticPrivateFieldGet(Account, _transactions).length;
}
});
var _makeTransaction = function(dollars, from, to) {
babelHelpers.classStaticPrivateFieldSet(Account, _transactions, babelHelpers.classStaticPrivateFieldGet(this, _transactions).concat(/* ... */));
};
var _transactions = [];
return Account;
}();Note that those implementation details are not final but a way to start the conversation and the actual implementation.