JavaScript: Public and private class fields

https://developers.google.com/web/updates/2018/12/class-fields
  • Transfer

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:


classIncreasingCounter{
  constructor() {
    this._count = 0;
  }
  get value() {
    console.log('Getting the current value!');
    returnthis._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:


classIncreasingCounter{
  _count = 0;
  get value() {
    console.log('Getting the current value!');
    returnthis._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:


classIncreasingCounter{
  #count = 0;
  get value() {
    console.log('Getting the current value!');
    returnthis.#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:


classFakeMath{
  // `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 :


classAnimal{
  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:


classCatextendsAnimal{
  constructor(name) {
    super(name);
    this.likesBaths = false;
  }
  meow() {
    console.log('Meow!');
  }
}

There is a lot of sample 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 :


classCatextendsAnimal{
  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.


Also popular now: