0

We have private members in Java and a lot of other Object Oriented Programming languages. Thus the title of the question is clear: How can we have private members in our JavaScript classes?

Let's consider the following example:

// PrivateMemberOwner.js
export default class PrivateMemberOwner {
    iAmPrivate () {
        console.log("I can not be accessed from Foo class' children!");
    }
    iAmPublic () {
        console.log("Anyone can call me from anywhere!");
    }
}

Then in my PrivateMemberOwnerExtension.js:

import PrivateMemberOwner from "./PrivateMemberOwner.js";

export default class PrivateMemberOwnerExtension extends PrivateMemberOwner {
    consumer () {
        // This one should work just fine:
        Foo.iAmPublic();

        // This one should throw some sort of error
        Foo.iAmPrivate();
    }
}

What is the right way of handling these?

Masious
  • 431
  • 5
  • 14
  • Nothing fundamentally has changed since ECMAScript 262 2nd Edition as of December 1999. Privacy in JavaScript still is achieved by declaring variables, function expressions etc within the local scope of other functions. Be it constructor functions or the function scope behind/of javascript modules. Thus there are at least 2 different approaches for the given example. This Q might be a duplicate of https://stackoverflow.com/questions/30191656/es6-classes-private-member-syntax that was a duplicate of https://stackoverflow.com/questions/22156326/private-properties-in-javascript-es6-classes – Peter Seliger Nov 21 '18 at 15:41

1 Answers1

0

In my opinion, having private members in JavaScript should satisfy these conditions:

  1. Being able to call iAmPrivate within the PrivateMemberOwner class. (As stated in the question)
  2. Not being able to call iAmPrivate anywhere outside the class definition. (At least not being able to call it accidentally)
  3. 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

  1. 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!');

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

Masious
  • 431
  • 5
  • 14