javascriptnode.jsclassecmascript-6symbols

Protected properties in ES6 classes (using Symbols?)


Question:

How would you implement protected properties in ES6 classes in an elegant way? (that can be accessed only from inside the child class)

I am not searching a response like "ES don't have protected/package properties". It is already known. I want a nice and cleaner workaround to emulate protected properties.

I don't want to add security. Only a cleaner exposed interface to all the end users of the API.


Example:

I have the following API: (node)

my-class.js:

let Symbols = {
    _secret: Symbol("_secret")
};
class MyClass {
    constructor() {
        this.public = "This is public";
        this[Symbols._secret] = "This is private";
    }
}
// Set the Symbols to a static propietry so any class can access it and extend it
MyClass[Symbol.for("_Symbols")] = Symbols;
module.exports = MyClass

my-child-class.js:

let MyClass = require("./my-class.js");

// extends protected properties with own properties
Symbols = Object.assign({}, MyClass[Symbol.for("_Symbols")] , {
    _childSecret = Symbol("_childSecret")
});

class MyChildClass extends MyClass {
    constructor() {
        super();
        this[Symbols._childSecret] = "This is also private";
        console.log(this[Symbols._secret]); //logs "this is private"
        console.log(this[Symbols._childSecret]); //logs "this is also private"
    }
}
// Set the Symbols to a static propietry so any class can access it and extend it
MyClass[Symbol.for("_Symbols")] = Symbols;
module.exports = MyChildClass;

To use the class:

let MyChildClass = require("./my-child-class.js");
var c = new MyChildClass();

The advantages:

The problem:


Solution

  • Your approach is pointless.

    Symbols do not provide any security because they are public. You can get them so easily with Object.getOwnPropertySymbols.

    So if you don't care about security and just want simplicity, use a normal _secret property.

    class MyClass {
      constructor() {
        this.public = "This is public";
        this._secret = "This is private";
      }
    }
    module.exports = MyClass;
    
    let MyClass = require("./my-class.js");
    class MyChildClass extends MyClass {
      constructor() {
        super();
        this._childSecret = "This is also private";
        console.log(this._secret); // "this is private"
        console.log(this._childSecret); // "this is also private"
      }
    }
    module.exports = MyChildClass;