📜 ⬆️ ⬇️

JavaScript: Public and private class fields

Several sentences extend existing class syntax in JavaScript with new functionality. This article explains the new class public field syntax in V8 v7.2 and Chrome 72, as well as the upcoming private fields.


Here is an example of the code that creates an instance of the IncreasingCounter class:


const counter = new IncreasingCounter(); counter.value; // logs 'Getting the current value!' // → 0 counter.increment(); counter.value; // logs 'Getting the current value!' // → 1 

Note that accessing value performs some code (outputting a message to the log) before returning a value. Now ask yourself: how would you implement this class in JavaScript?


ES2015 Classes


Below is an example of how the IncreasingCounter class can be implemented using the ES2015 syntax:


 class IncreasingCounter { constructor() { this._count = 0; } get value() { console.log('Getting the current value!'); return this._count; } increment() { this._count++; } } 

The class provides a getter value and a method for incrementing the value in the prototype. More curiously, the class has a constructor that triggers the _count property and sets its initial value to 0. We now use the underscore prefix to mean that _count should not be used directly outside the class, but this is just a convention; in reality, this is not a private property, and this semantics is not defined in the language itself.


 const counter = new IncreasingCounter(); counter.value; // logs 'Getting the current value!' // → 0 // Nothing stops people from reading or messing with the // `_count` instance property. counter._count; // → 0 counter._count = 42; counter.value; // logs 'Getting the current value!' // → 42 

Public class fields


The new syntax for public fields makes it easy to define a class:


 class IncreasingCounter { _count = 0; get value() { console.log('Getting the current value!'); return this._count; } increment() { this._count++; } } 

The _count property is now succinctly declared at the beginning of the class. We no longer need a constructor just to define some fields. Fine!


However, _count is still a public property. And in this particular example, we want to prevent accessing this field directly.


Private class fields


This is where private fields come to the rescue. The new syntax for private fields is similar to the syntax of public fields, except that you mark them as private using the # symbol . You may think that # is just part of the field name:


 class IncreasingCounter { #count = 0; get value() { console.log('Getting the current value!'); return this.#count; } increment() { this.#count++; } } 

Private fields are not available outside the body of the class:


 const counter = new IncreasingCounter(); counter.#count; // → SyntaxError counter.#count = 42; // → SyntaxError 

Static properties


Class field syntax can be used to create public and private static properties and methods, as shown below:


 class FakeMath { // `PI` is a static public property. static PI = 22 / 7; // Close enough. // `#totallyRandomNumber` is a static private property. static #totallyRandomNumber = 4; // `#computeRandomNumber` is a static private method. static #computeRandomNumber() { return FakeMath.#totallyRandomNumber; } // `random` is a static public method (ES2015 syntax) // that consumes `#computeRandomNumber`. static random() { console.log('I heard you like random numbers…') return FakeMath.#computeRandomNumber(); } } FakeMath.PI; // → 3.142857142857143 FakeMath.random(); // logs 'I heard you like random numbers…' // → 4 FakeMath.#totallyRandomNumber; // → SyntaxError FakeMath.#computeRandomNumber(); // → SyntaxError 

Simplify subclassing


The advantages of class field syntax become more obvious when working with subclasses that introduce additional fields. Imagine the following Base Animal class:


 class Animal { constructor(name) { this.name = name; } } 

To create a Cat subclass that adds a new property to an instance, you previously needed to call super () to call the constructor of the base Animal class before creating this property:


 class Cat extends Animal { constructor(name) { super(name); this.likesBaths = false; } meow() { console.log('Meow!'); } } 

There is a lot of template code just to indicate that cats do not like to take a bath. Fortunately, the new class field syntax eliminates the need to define this constructor with an awkward super () call:


 class Cat extends Animal { likesBaths = false; meow() { console.log('Meow!'); } } 

Total


Public class fields are available starting with V8 v7.2 and Chrome 72. It is planned to release private class fields soon.



Source: https://habr.com/ru/post/438202/