In my opinion, having private members in JavaScript should satisfy these conditions:
- Being able to call
iAmPrivate within the PrivateMemberOwner class. (As stated in the question)
- Not being able to call
iAmPrivate anywhere outside the class definition. (At least not being able to call it accidentally)
- The mechanism should leverage the prototype inheritance feature of JavaScript in order to consume less memory.
With that being said, the new Symbol type introduced in ES6 comes to mind.
Symbols are a primitive type introduced in ECMAScript 6, joining the existing primitive types: strings, numbers, booleans, null, and undefined.
(From Understanding ECMAScript 6 - by Nicholas C. Zakas)
So, let's get to the code:
// PrivateMemberOwner.js
const iAmPrivate = Symbol("iAmPrivate");
export default class PrivateMemberOwner {
[iAmPrivate] (message) {
console.log("I can not be accessed from Foo class' children!", message);
}
iAmPublic () {
console.log("Anyone can call me from anywhere!");
}
iAmPrivateUser () {
this[iAmPrivate]("I can access 'iAmPrivate' just fine.");
}
}
This way, we can have the iAmPrivateUser method access iAmPrivate method and make the children of PrivateMemberOwner class unable to access it. (at least accidental access to it)
Notes
As mentioned above, these kind of members are not fully private and the member [with some effort] can be accessed like this:
// ./PrivateReader.js
import PrivateMemberOwner from "./PrivateMemberOwner.js";
const privateMemberOwner = new PrivateMemberOwner();
const privateMemberOwnerSymbols = Object.getOwnPropertySymbols(privateMemberOwner);
const iWasPrivate = privateMemberOwner[privateMemberOwnerSymbols[0]];
iWasPrivate.call(privateMemberOwner, 'I just gained your access!');
Having private properties can be achieved the same way:
const barSymbol = Symbol('bar');
class Foo {
constructor () {
this[barSymbol] = null;
}
getBar () {
return this[barSymbol];
}
setBar (value) {
this[barSymbol] = value;
}
}