0

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.

  • 1
    `#privateMethod = () => {` will work just fine – CertainPerformance Aug 14 '21 at 02:08
  • I didn't think I was supposed to use arrow functions as methods per: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions I did notice that the this keyword seems to be working how I want it too. Is this documentation out of date? – Benjamin Peinhardt Aug 14 '21 at 02:15
  • 1
    It's not a method, it's a class field, which gets assigned to the instance. It's just fine to use. – CertainPerformance Aug 14 '21 at 02:16
  • Right so that I understand, the function is an object that is also a field of the class. But like... how does it access "this"? Also speed and memory wise is building the method for every instance an issue or is it just not a big deal? – Benjamin Peinhardt Aug 14 '21 at 02:21
  • I'm used to compilers so I'm not used to thinking about stuff built at runtime. – Benjamin Peinhardt Aug 14 '21 at 02:29
  • I don't see how private class fields have anything to do with lexical `this`. – Bergi Aug 14 '21 at 04:58
  • While things like mockability and inheritance don't apply to private class fields, I still would recommend [not to use arrow functions in class fields](https://www.charpeni.com/blog/arrow-functions-in-class-properties-might-not-be-as-great-as-we-think) in general. Especially if you don't need arrow functions. – Bergi Aug 14 '21 at 05:02
  • I don't get how you arrived at the pattern from the first snippet (with the `Private` class). Yes, this looks like an unreadable "*mess of a strategy*", what were you trying to achieve with that? – Bergi Aug 14 '21 at 05:04
  • @Bergi I was trying to achieve private and public methods with access to each other and the same instance of the class using the ES6 class syntax, because I did not know syntax for private methods had been added to the language already. – Benjamin Peinhardt Aug 14 '21 at 07:07
  • @BenjaminPeinhardt Where did you learn about private fields? They were added together with private methods. – Bergi Aug 14 '21 at 11:54

1 Answers1

0

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.

MinusFour
  • 13,913
  • 3
  • 30
  • 39