DEV Community

Cover image for Private class fields in Javascript (ES2022)
Smitter
Smitter

Posted on • Edited on

Private class fields in Javascript (ES2022)

Class fields and class methods are public by default.
It is common you may want to make your class fields private. If you come from a Java background, you may achieve this with the private keyword inside of a Java class definition. JavaScript has lacked such a feature since its inception.

Article Sections

  1. How to create a private class field
  2. Inheritance
  3. Weird syntax? Why not use private keyword?

How to create a private class field

As of ES2022, you can define private fields for a class using # sign prefixed to the identifiers. You can access private fields from the class constructor within the class declaration.

For example, the following defines the Circle class with a private field radius:

class Circle {
  // private field
  #radius;
  constructor(value) {
    // You can access private field from constructor
    this.#radius = value;
  }
  get area() {
    return Math.PI * Math.pow(this.#radius, 2);
  }
}
Enter fullscreen mode Exit fullscreen mode

From the above example,

  • We declare private field #radius in the body of the class
  • We initialize the #radius field in the constructor with an argument.
  • We calculate the area of the circle by accessing the #radius private field in the getter method.

The following creates a new instance of the Circle class and calculates its area:

const circle = new Circle(10);
console.log(circle.area); // 314.1592653589793
Enter fullscreen mode Exit fullscreen mode

Now that the #radius is a private field, you can only access it inside the Circle class. In other words, the #radius field is invisible outside of the Circle class.

Trying to access the private field outside of the class will generate a syntax error:

console.log(circle.#privateField);   // Syntax error
Enter fullscreen mode Exit fullscreen mode

Inheritance

Like public fields, private fields are added at construction time in a base class, or at the point where super() is invoked in a subclass. But trying to access Private field from a subclass will result in SyntaxError. Private fields are only accessible in the enclosing class (class where they’re defined). For example, the following defines the Cylinder class that extends the Circle class:

class Cylinder extends Circle {
  #height;
  cRadius;
  constructor(radius, height) {
    super(radius);
    this.#height = height;

    // cannot access the #radius of the Circle class here
    this.cRadius = this.#radius // Syntax Error
  }
}
Enter fullscreen mode Exit fullscreen mode

If you attempt to access the #radius private field in the Cylinder class, you’ll get a SyntaxError.

Weird syntax? Why not use private keyword?

Class definitions were introduced in ES6 and the public opinion remained cool. ES2019 class fields require less code, aid readability, and enable some interesting object-oriented programming possibilities.

Using # to denote private fields has received some criticism, primarily because it’s ugly and feels like a hack.

Most languages implement a private keyword, so attempting to use that member outside the class will be rejected by the compiler. JavaScript is interpreted. Consider the following code:

NOTE: Vanilla Javascript does not support private keyword but it won't hurt to assume for now that the private keyword in classes is supported.

class MyCircle {
  private rad = 15;
  #radius
}

const myCircle = new MyCircle();
myCircle.rad = 20;
Enter fullscreen mode Exit fullscreen mode

After instantiating our class(const myCircle = new MyCircle();), we are trying to access the private rad property(myCircle.rad = 20;).This would have thrown a runtime error on the last line, but that’s too much consequence for simply attempting to set a private property.
As you may not know, JavaScript ES5 permitted property modification on any object. Javascript classes are objects under the hood. So throwing a runtime error for trying to set a private property of our class is really like setting your own rules/conventions up in flames🔥.

Although insipid to the eyes, the # notation is invalid outside a class definition. Attempting to access myCircle.#radius throws a syntax error.
The syntax error is logical since in Javascript, property names may either start with an underscore or a letter.

Hit the like button and please consider following me on twitter to keep abreast with what am upto these days. Follow me here in dev.to to stay tuned when my next article comes up! Peace✌️

Top comments (2)

Collapse
 
irina_kats profile image
Irina Kats

Thanks, very helpful explanation of the syntax! It did not make sense why "private" was working in TS but not in JS. Now I know, this was just what I was looking for!

Collapse
 
smitterhane profile image
Smitter

Yes Javascript is such a wonderful language