Публичные и приватные поля классов

Powered by Google Translate

Несколько предложений расширяют существующий синтаксис классов в 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. Скоро планируется релиз и приватных полей классов.

У Вас есть вопросы о новых возможностях языка? Комментарии к этой статье? Не стесняйтесь писать мне в Твиттер @mathias!

Обратная связь

Was this page helpful?
Yes
What was the best thing about this page?
It helped me complete my goal(s)
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.
It had the information I needed
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.
It had accurate information
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.
It was easy to read
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.
Something else
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.
No
What was the worst thing about this page?
It didn't help me complete my goal(s)
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.
It was missing information I needed
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.
It had inaccurate information
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.
It was hard to read
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.
Something else
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.

rss_feed Subscribe to our RSS or Atom feed and get the latest updates in your favorite feed reader!