Private static and instance properties/accessor properties/methods of classes in Javascript are currently at stage 3 of the TC39 standardization process (see here). My idea is based on that work. Most OOP languages (e.g. Java, C++ and even TypeScript) do not only have public and private access modifiers but also a kind of protected access modifier which is currently missing in Javascript/ECMAScript.
As Javascript uses the # character to indicate private members of classes and no access modifier at all for public access to members of classes, it seems not to be a good idea to use a protected
keyword for protected members of classes in Javascript as it is used in Java, C++, or TypeScript. Furthermore, there are some ideas and a proposal (see ideas for use of class static blocks, proposal) to extend the normal use case of protected class members (restrict access to the class and its subclasses) to be able to access them from unrelated classes or even external functions which are not related to the class.
I think that a general principle should be kept: A class should control which external entites are allowed to access class members with restricted access modifiers, and all the logic, code, and data concerned to access restrictions should be part of the class itself. Therefore, no external variables should be needed to get access to class members with restricted access modifiers as it is used in the examples of the ideas and the proposal mentioned above. The principle is important as it keeps an OOP mindset.
My idea is two-fold:
- Introduce a new character for the beginning of an identifier name to signal protected access for the corresponding class member similar to the
protected
keyword in other OOP languages (e.g. Java, C++). As Javascript already uses many of the characters available on normal keyboards, and to prevent ambiguous character reuse, I suggest the use of the§
character for protected class members. Other suggestions are welcome.; - Open access to protected and private class members for unrelated "friend" classes. As they are "friends", I want to suggest to introduce the keywords friend and friends but that is only one option which can be substituted.
To clarify my idea, I want to give same examples:
a) Use of identifiers beginning with an § character to define protected class members (open access to class members of the base class A for subclass B):
class A {
§x = 0;
get §valueX() { return §x; }
set §valueX(x) { §x = x; }
§addToX(value) { §x += value; }
static §sx = 1;
static get §valueSX() { return §sx; }
static set §valueSX(sx) { §sx = sx; }
static §addToSX(value) { §sx += value; }
}
class B extends A {
instanceAccess() {
§x++; // access to #x of base class A
§valueX += 2; // access to get/set #valueX() of base class A
§addtoX(4); // access to #addToX(value) of base class A
}
static staticAccess() {
§sx++; // access to #sx of base class A
§valueSX += 2; // access to get/set #valueSX() of base class A
§addtoSX(4); // access to #addToSX(value) of base class A
}
}
b) Use of the keyword friends
and friend
to open access to class members of class A for an unrelated class C:
class A friends C {
// private instance members become friends
friend #x = 0;
friend get #valueX() { return #x; }
friend set #valueX(x) { #x = x; }
friend #addToX(value) { #x += value; }
// protected instance members become friends
friend §y = 0;
friend get §valueY() { return §y; }
friend set §valueX(x) { §x = x; }
friend §addToX(value) { §x += value; }
// private static members become friends
friend static #sx = 1;
friend static get #valueSX() { return #sx; }
friend static set #valueSX(sx) { #sx = sx; }
friend static #addToSX(value) { #sx += value; }
// protected static members become friends
friend static §sy = 1;
friend static get §valueSY() { return §sx; }
friend static set §valueSY(sx) { §sx = sx; }
friend static §addToSX(value) { §sx += value; }
}
class C {
instanceAccess() {
const objA = new A();
objA.#x++; // access to #x of unrelated class A
objA.#valueX += 2; // access to get/set #valueX() of unrelated class A
objA.#addtoX(4); // access to #addToX(value) of unrelated class A
objA.§y++; // access to §y of unrelated class A
objA.§valueY += 2; // access to get/set §valueY() of unrelated class A
objA.§addtoY(4); // access to §addToY(value) of unrelated class A
}
static staticAccess() {
A.#sx++; // access to #sx of unreleated class A
A.#valueSX += 2; // access to get/set #valueSX() of unrelated class A
A.#addtoSX(4); // access to #addToSX(value) of unrelated class A
A.§sx++; // access to §sx of unreleated class A
A.§valueSY += 2; // access to get/set §valueSY() of unrelated class A
A.§addtoSY(4); // access to §addToSY(value) of unrelated class A
}
}
Other considerations for protected methods:
a) Protected methods should be overwriteable in subclasses;
b) The access modifier of a method in a subclass which overrides a protected method of a base class needs to be at least as accessible as the base class method;
c) Public methods of a base class must not be overriden by a protected method of a subclass;
Other open questions:
a) Are there alternative characters to §?