Private class fields in Javascript (ES2022)
Tags: javascript, webdev, programming, tutorial
Published: 2022-04-25 14:39:07

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](#how-to-create-a-private-class-field)
2. [Inheritance](#inheritance)
3. [Weird syntax? Why not use `private` keyword?](#weird-syntax-why-not-use-raw-private-endraw-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`:

```javascript
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);
  }
}
```

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:

```javascript
const circle = new Circle(10);
console.log(circle.area); // 314.1592653589793
```

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:

```javascript
console.log(circle.#privateField);   // Syntax error
```

### 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:

```javascript
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
  }
}
```
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.

```javascript
class MyCircle {
  private rad = 15;
  #radius
}

const myCircle = new MyCircle();
myCircle.rad = 20;
```

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](https://twitter.com/smitterhane) 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✌️_