javascriptnode.jses6-classprivate-membersprivate-methods

ES6 Private Methods with access to "this" keyword JavaScript idioms


I'm learning JavaScript and NodeJS as I go for a work project and have been making heavy use of ES6 classes over ProtoTypes. I would like to use private methods or something like private methods, but it seems like this is not a feature of JavaScript classes yet. Are there any common patterns for this with ES6 classes? So far I've devised this mess of a strategy:

class Private {
    constructor(pub) {
        this.pub = pub;

        this.privateAttribute = "Private Attribute\n";
    }

    privateMethod() {
        process.stdout.write('Private Method\n');
    }

    privateMethodCallsPublicMethod() {
        this.pub.publicMethod();
    }

    privateMethodUsesPublicAttribute() {
        process.stdout.write(this.pub.publicAttribute);
    }
}

class aClass {
    #private = new Private(this);

    constructor() {
        this.publicAttribute = "Public Attribute\n";
    }

    publicMethod() {
        process.stdout.write('Public Method\n')
    }

    publicMethodCallsPrivateMethod() {
        this.#private.privateMethod();
    }

    publicMethodUsesPrivateAttribute() {
        process.stdout.write(this.#private.privateAttribute);
    }

    privateMethodsHaveAccessToPublicMethods() {
        this.#private.privateMethodCallsPublicMethod();
    }

    privateMethodsHaveAccessToPublicAttributes() {
        this.#private.privateMethodUsesPublicAttribute();
    }
}

module.exports = { aClass };

as well as

class aClass {
    
    #privateAttribute = "Private Attribute\n";

    constructor() {
        this.publicAttribute = "Public Attribute\n";
    }

    publicMethod() {
        process.stdout.write('Public Method Called\n');
    }

    #privateMethod = () => {
        process.stdout.write('Private Method Called\n');
    }

    publicMethodCallsPrivateMethod() {
        this.#privateMethod();
    }

    publicMethodUsesPrivateAttribute() {
        process.stdout.write(this.#privateAttribute);
    }

    #privateMethodCallsPublicMethod = () => {
        this.publicMethod();
    }

}

module.exports = { aClass };

But I'm pretty new to JavaScript and don't know how these work in terms of:

  1. The lexical this, especially scoping
  2. Implications on memory allocation and performance
  3. Readability for JavaScripters

Not to mention it just doesn't look nice. I wouldn't mind learning ProtoTypes if need be, I actually like the way things separate (I program mostly in Rust and C so mentally I don't usually think in Classes), but I'd like to be writing "Modern JavaScript" and more importantly readable, familiar JavaScript if possible and I just have no instinct for what that looks like.


Solution

  • Private methods are safe now (they are finally stage 4 after a long time). If your browser supports it this should work:

    class A {
      #myPrivateMethod(){
         console.log('this is my private method');
      }
      constructor(){
         this.#myPrivateMethod();
      }
    }
    
    new A;

    this should work as expected. Depending on the context.

    class A {
      #myPrivateMethod(){
         console.log(this);
      }
      constructor(){
         this.#myPrivateMethod();
         this.#myPrivateMethod.call('someotherthis');
      }
    }
    
    new A;

    It is different from an arrow function in a class field initializer, in which this is the constructed object. In your example, this belongs to the Private object being constructed although you can call those methods with a different this through .call and .apply.

    As for memory allocation that will depend on the implementation which I do not know how any handles it. I do believe they are the same function object though, private methods that is. Your example however does use different Private objects for each instance, though each method is still unique. A class field would create multiple function objects as well.