Несколько предложений расширяют существующий синтаксис классов в JavaScript новой функциональностью. Эта статья объясняет новый синтаксис публичных полей классов в V8 v7.2 и Chrome 72, а также грядущих приватных полей.
Вот пример кода, который создает экземпляр класса IncreasingCounter:
const counter = new IncreasingCounter(); counter.value; // logs 'Getting the current value!' // → 0 counter.increment(); counter.value; // logs 'Getting the current value!' // → 1
Отметим, что обращение к value выполняет некоторый код (вывод сообщения в лог) перед тем, как вернуть значение. Теперь спросите себя: как бы Вы реализовали этот класс на JavaScript?
Классы ES2015
Ниже пример того, как класс IncreasingCounter может быть реализован с помощью синтаксиса ES2015:
class IncreasingCounter { constructor() { this._count = 0; } get value() { console.log('Getting the current value!'); return this._count; } increment() { this._count++; } }
Класс предоставляет геттер value и метод для инкремента значения в прототипе. Более любопытно, что класс имеет конструктор, который инициирует свойство _count и выставляет его начальное значение в 0. Сейчас мы используем префикс подчеркивания, чтобы обозначить, что _count не должен использоваться напрямую вне класса, но это просто соглашение; в действительности это не приватное свойство, а эта семантика не определена в самом языке.
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
Публичные поля классов
Новый синтаксис для публичных полей позволяет упростить определение класса:
class IncreasingCounter { _count = 0; get value() { console.log('Getting the current value!'); return this._count; } increment() { this._count++; } }
Свойство _count теперь лаконично объявлено в начале класса. Нам больше не нужен конструктор только для того, чтобы определить некоторые поля. Отлично!
Тем не менее, _count — все еще публичное свойство. А в этом конкретном примере мы хотим предотвратить обращение к этому полю напрямую.
Приватные поля классов
Именно здесь на помощь приходят приватные поля. Новый синтаксис для приватных полей схож с синтаксисом публичных полей, за исключением того, что Вы помечаете их как приватные, используя символ #. Вы можете думать, что # — это просто часть имени поля:
class IncreasingCounter { #count = 0; get value() { console.log('Getting the current value!'); return this.#count; } increment() { this.#count++; } }
Приватные поля недоступны вне тела класса:
const counter = new IncreasingCounter(); counter.#count; // → SyntaxError counter.#count = 42; // → SyntaxError
Статические свойства
Синтаксис полей классов может быть использован для создания публичных и приватных статических свойств и методов, как показано ниже:
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
Упрощение работы с подклассами
Преимущества нового синтаксиса полей классов становятся более очевидны при работе с подклассами, которые вводят дополнительные поля. Представим следующий базовый класс Animal:
class Animal { constructor(name) { this.name = name; } }
Чтобы создать подкласс Cat, который добавляет новое свойство для экземпляра, ранее требовалось обратиться к super(), чтобы вызвать конструктор базового класса Animal перед тем, как создать это свойство:
class Cat extends Animal { constructor(name) { super(name); this.likesBaths = false; } meow() { console.log('Meow!'); } }
Здесь много шаблонного кода только для того, чтобы указать, что коты не очень любят принимать ванну. К счастью, новый синтаксис полей классов избавляет от необходимости определения этого конструктора с неуклюжим вызовом super():
class Cat extends Animal { likesBaths = false; meow() { console.log('Meow!'); } }
Итого
Публичные поля классов доступны, начиная с V8 v7.2 и Chrome 72. Скоро планируется релиз и приватных полей классов.
