Privates In ES2015 Javascript Classes

Last updated: September 3, 2015

One feature missing in ES2015 (formerly ES6) classes is the concept of a private variable or function. However, thanks to ES2015 modules we can actually easily define private properties and functions that can only be accessed within our class.

Private Properties in ES2015 classes

Using a WeakMap which we have discussed before, we are going to implement the concept of private class properties.

Because classes are just objects, we can use WeakMaps on them. Then by specifying getter and or setter methods on the class, we can control access to these private properties. The beautiful thing about this is that using the export keyword, we are only exposing the class Person. This is akin to the revealing module pattern where we choose what is exposed to the client.

Using something like an ES2016 Decorator, we can probably easily create the concept of a decorator which will allow us to define variables as private and even control access to them. Just some food for thought.

const privateProps = new WeakMap();

export class Person {
    constructor(name, dob) {
        privateProps(this, {name: name, dob: dob});
    }

    get name() {
        return privateProps.get(this).name;
    }

    get dob() {
        return privateProps.get(this).dob;
    }
}

Private Methods

We are going to be borrowing the above example and introducing the concept of a private method. The goal of our private method is to only be used within the class itself, but not available to the client by any other means.

Traditionally the revealing module pattern allowed us to selectively choose what is exposed, we can achieve the same thing using ES2015 modules (like above).

const privateProps = new WeakMap();

// Private function for lowercasing a string
function _convertToLowercase(val) {
    return val.toLowerCase();
}

export class Person {
    constructor(name, dob) {
        privateProps(this, {name: name, dob: dob});
    }

    get name() {
        return _convertToLowercase(privateProps.get(this).name);
    }

    get dob() {
        return privateProps.get(this).dob;
    }
}

In our example above we create a rather redundant private method for lowercasing a string. The function _convertToLowercase is only accessible from within the class itself. Because we are exporting the class, it doesn’t get exposed. This allows us to have the concept of a private method very easily.

I realise the private method is not on the class itself and that would be the ideal situation to be in. But given how classes actually operate, any method you currently define in the class gets added to the prototype of your class so it can be called from anywhere.

Conclusion

While ES2015 Javascript lacks the concept of visibility keywords, we can still achieve the same thing without them. This is why I really like Javascript, it doesn’t give you one way or the highway, but lets you implement hacks creative solutions to problems.

Supersets like TypeScript while they have concepts of visibility keywords, they’re not for the resulting output but only for the compiling stage where your code is checked. It will stop you if you are trying to illegally reference a private property or method.

Liked it? Take a second to support Dwayne on Patreon!
 

Dwayne

 

5 thoughts on “Privates In ES2015 Javascript Classes

  1. Uhhhh…I think you haven’t heard of ES6 symbols.

    “`
    let _name = Symbol();
    let _dob = Symbol();

    export default class Person {
    constructor(name, dob) {
    this[_name] = name;
    this[_dob] = dob;
    }

    get name() {
    return _convertToLowercase(this[_name]);
    }

    get dob() {
    return this[_dob];
    }
    }
    “`

    Only code that has access to `_name` and `_dob` can access those properties of your class instances.

    The polyfills for both Symbols and WeakMap end up just sticking the private properties inside a hidden object hierarchy on your object anyway 🙂

    Sometimes I think this is all a step backward from old-school JS anyway:

    “`
    function Person(name, dob) {
    return {
    name: function() {
    return name;
    }
    dob: function() {
    return dob;
    }
    }
    }
    “`

  2. Symbols are unique (like gensym), but not private since they are exposed via reflection features like Object.getOwnPropertySymbols.

  3. Pingback: Nimlos Development
  4. privateProps(this, {name: name, dob: dob}); -> privateProps.set(this, {name: name, dob: dob});

Leave a Reply

Your email address will not be published. Required fields are marked *