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;
}
}