8

I'm trying to define a private method for a class to test that such a method can't be called from outside the class. However, I'm coming across an error even when I'm using the syntax as indicated in the Specification. I also checked MDN.

Here's the code for my class:

class CoffeeMachine {
  #waterLimit = 200;

  #checkWater(value) {
    if (value < 0) throw new Error("Negative water");
    if (value > this.#waterLimit) throw new Error("Too much water");
  }
}

const coffeeMachine = new CoffeeMachine;

coffeeMachine.#checkWater();

Upon calling coffeeMachine.#checkWater();, I'm supposed to get an error indicating that such a method can't be called from outside the class, but instead, I'm getting Uncaught SyntaxError: Unexpected token '('.

What could be the reason for this?

connexo
  • 53,704
  • 14
  • 91
  • 128
Mauric.io
  • 111
  • 1
  • 2
  • 6
  • Very serious question: you're in JS, what do you _actually_ need private properties for? But on top of that, unless you intend for nothing to be able to call `coffeemachine.checkWater()`, don't mark that as private. Setting the `waterLimit` as a private property maybe makes sense, but that function sure looks like it's supposed to be a normal function that anything should be able to call. Also note that it's not officially part of JS yet. It's currently in stage 3 (link in the MDN article) – Mike 'Pomax' Kamermans Nov 20 '19 at 20:20
  • 1
    If you tried this in a browser it most likely isn't supported yet [check the compatibility tables](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Class_fields#Private_class_fields) for private method syntax – Patrick Evans Nov 20 '19 at 20:23
  • 2
    @mike because somewhen someone will think *Oh, I could refactor that piece properly or I rather just use that `_private` property* ... and then it ain't private anymore – Jonas Wilms Nov 20 '19 at 20:45
  • 1
    I don't intend to achieve anything particularly useful with this, but I just figured out that if I set `#checkWater` as private property and assign a function to it (rather than defining it as a private method), it throws the error `Uncaught SyntaxError: Private field '#checkWater' must be declared in an enclosing class`. Which, to be honest, I'm not sure whether it is the expected behavior. Anyway, as @mike – Mauric.io Nov 20 '19 at 20:52
  • Anyway, as @mike mentioned, this is not implemented yet, this way of assigning a function to a Private property (to get a Private method) is just an option, given that Private methods are just immutable own Private fields which are functions. I guess I can't help but wait to see whether this proposal makes it to the final stage. – Mauric.io Nov 20 '19 at 21:04
  • 1
    @mike no, not really. In a larger project not. Everybody has it's own playground there and you don't step onto someone elses grass without their permission. *code ownership* you know ... – Jonas Wilms Nov 20 '19 at 22:03

5 Answers5

7

In Javascript, you need to declare private variables private variables are declared by putting "#" in front of them (as seen in my example). Be sure to declare them outside of the constructor function

    class foo {
        #bar;// declare private variable called bar

        constructor() {
            this.#bar = "foobar";//define private variable called"bar"
        }
    }
Yureadingthis
  • 71
  • 1
  • 2
2

I think private methods (#myMethod()) and fields (#myField) are experimental features [source: developer.mozilar.org ] and at stage 3 for consideration but I managed to make it work by defining it to be as field and assigning it a function as follows;

#checkWater = (value) => {
  if (value < 0) throw new Error("Negative water");
  if (value > this.#waterLimit) throw new Error("Too much water");
}

OR

#checkWater = function(value) {
  if (value < 0) throw new Error("Negative water");
  if (value > this.#waterLimit) throw new Error("Too much water");
}

Now call it on the instance object as

coffeeMachine.#checkWater();

Let me hasten to add that, this code works in Google Chrome (1st image) but when tested in FireFox (2nd image), it did not run.

enter image description here

enter image description here

You should be okay with it hopefully!

bafrimpong
  • 99
  • 11
  • Your approach gives me `Uncaught SyntaxError: Private field '#checkWater' must be declared in an enclosing class` in current Chrome. I expected it wouldn't work, but I don't exactly find the error message helpful. – connexo Oct 07 '20 at 15:13
  • @connexo make sure that you have the method within a class. e.g. `Class Test { #checkWater = function(value) { if (value < 0) throw new Error("Negative water"); if (value > this.#waterLimit) throw new Error("Too much water"); } }` – bafrimpong Oct 08 '20 at 16:37
  • Ofc it's in a class, otherwise you cannot declare private properties. – connexo Oct 08 '20 at 19:58
1

You example works in my Node.js 14.13.0 environment! Of course you need a public method to consume a private one. So here my working example:

   class CoffeeMachine {
     #waterLimit = 200

     #checkWater(value) {
       if (value < 0) throw new Error("Negative water")
       if (value > this.#waterLimit) throw new Error("Too much water")
       console.log(`@VALUE ${value}`)
     }

     checkWater(value) {
       this.#checkWater(value)
     }
   }

   const coffeeMachine = new CoffeeMachine()
   coffeeMachine.checkWater(20)
MikeM
  • 13,156
  • 2
  • 34
  • 47
cicciosgamino
  • 871
  • 3
  • 10
  • 29
0

You are trying to access a private method from outside its class.

For environments with support for private fields, the following error is returned instead with the same code:

SyntaxError: Private field '#checkWater' must be declared in an enclosing class

This is expected behaviour. You may only access private fields within their enclosing class and only if they are declared. Any attempt to access private fields outside of their containing class (where they are not declared), including fields and classes that are not declared, will result in this syntax error.

For instance:

  • Chrome 94 (DevTools)
    Cannot access private fields from outside of enclosing class on Chrome 94
    Syntax error instead of ReferenceError

  • Node 14.7.4 (REPL server)
    Cannot access private fields from outside of enclosing class on Node v14

  • Your browser

    class CoffeeMachine {};
    const coffeeMachine = new CoffeeMachine;
    coffeeMachine.#notDeclared;

See more in the ECMAScript private class fields proposal (repo @tc39/proposal-private-fields, now part of @tc39/proposal-class-fields, stage 3).

undefined
  • 1,019
  • 12
  • 24
0

Might that be that you didn't actually instantiated the class instance in here:

 const coffeeMachine = new CoffeeMachine; 

It should be

const coffeeMachine = new CoffeeMachine();

(Notice the parenthesis () )

Nez Nez
  • 33
  • 5