Новые #приватные поля классов в JavaScript

Andrey Melikhov
Jun 23, 2017 · 5 min read

Что это такое, как оно работает, и почему так выглядит

Перевод статьи James Kyle: JavaScript’s new #private class fields. Распространяется по лицензии CC BY 4.0.

Эта статья лучше всего идёт под музыку: “Noise Pollution” — Portugal. The Man

Приватные поля классов в процессе стандартизации JavaScript добрались до Stage 2. Это еще не финальная стадия, но комитет по стандартам JavaScript ожидает, что эта возможность будет разработана и в конечном итоге включена в стандарт (хотя она все еще может измениться).

Синтаксис (в настоящее время) выглядит так:

  constructor(x, y) {
this.#x = x;
this.#y = y;
}
equals(point) {
return this.#x === point.#x && this.#y === point.#y;
}
}

В этом синтаксисе есть две важные части:

  1. Объявление приватных полей;
  2. Обращение к приватным полям.

Объявление приватных полей

Объявление приватных полей в основном совпадает с объявлением публичных полей:

Чтобы получить доступ к приватному полю, вам необходимо объявить его. При желании можно объявить поле и не записывая в него никакое значение:

Обращение к приватным полям

Ссылка на приватные поля работает аналогично доступу к любому другому свойству, только она имеет специальный синтаксис.

Также есть краткая форма записи для this.#:

Это то же самое, что:

Обращение к приватным полям экземпляров класса

Обращение к приватным полям не ограничивается this. Вы также можете получить доступ к приватным полям экземпляров вашего класса:

Foo.getPrivateValue(new Foo()); // >> 42

Здесь foo является экземпляром Foo, поэтому нам разрешено обращаться к #privateValue из описания класса.

Приватные методы (скоро будут?)

Приватные поля являются частью предложения, посвященного добавлению полей классов. Предложение не вносит никаких изменений в методы класса, поэтому приватные методы класса ожидаются в следующем предложении и, скорее всего, будут выглядеть следующим образом:

Тем временем вы все равно можете присваивать приватным полям функции:

  #method = () => {
// ...
};
}

Инкапсуляция

Если вы используете экземпляр класса, вы не можете ссылаться на приватные поля этого класса. Вы можете ссылаться на приватные поля только внутри класса, который их определяет.

Кроме того, чтобы поля оставались действительно приватными, вы не сможете даже обнаружить их существование.

Чтобы быть уверенными, что вы не можете обнаружить частное поле, нам нужно разрешить объявление публичного поля с тем же именем.

Если частные поля не разрешают публичные поля с тем же именем, вы можете обнаружить существование приватных полей, попытавшись объявить свойство с тем же именем:

Или тихая версия (без вывода ошибки):

Эта инкапсуляция также должна быть верна для подклассов. Подкласс должен иметь возможность иметь одноименное поле, не беспокоясь о родительском классе.

class Bar extends Foo {
fieldName = 2; // Работает!
}

Примечание: Для получения дополнительной информации о важности инкапсуляции или «жесткой приватности», прочитайте этот раздел в FAQ.

Итак, почему хэштег?

Многие люди задаются вопросом: «Почему бы не следовать соглашениям из других языков и не использовать ключевое слово private»?

Вот пример такого синтаксиса:

  equals(foo) {
return this.value === foo.value;
}
}

Давайте рассмотрим две части этого синтаксиса отдельно.

Почему объявления не используют ключевое слово private?

Ключевое слово private используется в множестве разных языков для объявления приватных полей.

Давайте посмотрим на синтаксис такого языка:

В таких языках доступ к публичным и приватным полям осуществляется одинаково. Поэтому такое определение имеет смысл.

Тем не менее, в JavaScript, поскольку мы не можем использовать this.field для приватных свойств (почему — объясню ниже), нам нужен иной способ синтаксической связи. Использование # в обоих случаях делает отсылку наиболее понятной (мы сразу видим, что ссылаемся на приватное свойство).

Зачем нужен #хештег в обращении?

Нам нужно использовать this.#field вместо this.field по нескольким причинам:

  1. Из-за #инкапсуляции (см. раздел «Инкапсуляция» выше), мы должны разрешить создавать публичные и приватные поля с одним и тем же именем. Поэтому доступ к приватному полю не может быть обычным поиском в объекте.
  2. К публичным полям в JavaScript можно обратиться через this.field или this['field']. Приватные поля не смогут поддерживать второй синтаксис (потому что они должны быть статичным), что может привести к путанице.
  3. Вам не потребуются дорогие проверки.

Давайте рассмотрим пример кода.

  constructor(x, y) {
this.#x = x;
this.#y = y;
}
equals(other) {
return this.#x === other.#x && this.#y === other.#y;
}
}

Обратите внимание, как мы ссылаемся на other.#x и other.#y. Получая доступ к приватным полям, мы предполагаем, что other является экземпляром (instanceof) нашего класса Point.

Поскольку мы использовали синтаксис #хештег, мы сказали компилятору JavaScript, что мы просматриваем приватные свойства текущего класса.

Но что произойдет, если мы не будем использовать #хештег?

Теперь у нас есть проблема: как мы узнаем, что такое otherPoint?

JavaScript не имеет системы статической типизации, поэтому otherPoint может быть чем угодно.

Это проблема по двум причинам:

  1. Наша функция ведет себя по-разному в зависимости от того, значения какого типа вы передаете ей: иногда доступ к приватному свойству, в другое время — поиск публичного свойства.
  2. Нам нужно будет проверять тип otherPoint каждый раз:

Хуже того, нам нужно было бы сделать это для каждого доступа к свойствам в классе, чтобы проверить, ссылаемся ли мы на приватное свойство или нет.

Доступ к свойствам и так очень медленный, поэтому мы определенно не хотим добавлять к нему ещё больше веса.

TL;DR: Нам нужно использовать #хештег для приватных свойств, потому что использование стандартного доступа к свойствам повлечёт неожиданное поведение и приведет к огромным проблемам с производительностью.

Приватные поля — отличное дополнение к языку. Спасибо всем замечательным трудолюбивым людям из TC39, которые сделали/делают их возможными!

Слушайте наш подкаст в iTunes и SoundCloud, читайте нас на Medium, контрибьютьте на GitHub, общайтесь в группе Telegram, следите в Twitter и канале Telegram, рекомендуйте в VK и Facebook.

Статья на GitHub

devSchacht

Подкаст. Переводы. Веб-разработка.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store