В TypeScript 3.8+, каковы различия между использованием private
ключевого слова для пометки члена как частного:
class PrivateKeywordClass {
private value = 1;
}
И используя #
частные поля, предлагаемые для JavaScript :
class PrivateFieldClass {
#value = 1;
}
Должен ли я предпочесть один другому?
javascript
typescript
class
encapsulation
Мэтт Бирнер
источник
источник
Ответы:
Приватное ключевое слово
Частное ключевым словом в машинописном является компиляцией времени аннотаций. Он сообщает компилятору, что свойство должно быть доступно только внутри этого класса:
Однако проверку времени компиляции можно легко обойти, например, отбрасывая информацию о типе:
private
Ключевое слово также не соблюдается во время выполненияИспускаемый JavaScript
При компиляции TypeScript в JavaScript
private
ключевое слово просто удаляется:становится:
Отсюда видно, почему
private
ключевое слово не обеспечивает никакой защиты во время выполнения: в сгенерированном JavaScript это просто обычное свойство JavaScript.Частные поля
Частные поля гарантируют, что свойства остаются частными во время выполнения :
TypeScript также выведет ошибку времени компиляции, если вы попытаетесь использовать приватное поле вне класса:
Закрытые поля приходят из предложения JavaScript, а также работают в обычном JavaScript.
Испускаемый JavaScript
Если вы используете закрытые поля в TypeScript и нацеливаетесь на более ранние версии JavaScript для вывода, например,
es6
илиes2018
, TypeScript попытается сгенерировать код, который имитирует поведение закрытых полей во время выполненияЕсли вы нацеливаетесь
esnext
, TypeScript выдаст приватное поле:Какой из них я должен использовать?
Это зависит от того, чего вы пытаетесь достичь.
private
Ключевым словом является штраф по умолчанию. Он выполняет то, для чего был разработан, и успешно используется разработчиками TypeScript в течение многих лет. И если у вас есть существующая кодовая база, вам не нужно переключать весь код на использование приватных полей. Это особенно верно, если вы не нацеливаетесьesnext
, поскольку JS, который TS генерирует для частных полей, может повлиять на производительность. Также имейте в виду, что частные поля имеют другие тонкие, но важные отличия отprivate
ключевого слова.Однако, если вам нужно обеспечить конфиденциальность во время выполнения или вывести
esnext
JavaScript, вам следует использовать закрытые поля.Также имейте в виду, что соглашения организации / сообщества об использовании одного или другого также будут развиваться по мере того, как частные поля станут более распространенными в экосистемах JavaScript / TypeScript.
Другие отличия примечания
Закрытые поля не возвращаются
Object.getOwnPropertyNames
и аналогичными методамиЧастные поля не сериализуются
JSON.stringify
Существуют крайние случаи важности вокруг наследования.
Например, TypeScript запрещает объявлять частное свойство в подклассе с тем же именем, что и частное свойство в суперклассе.
Это не так с частными полями:
private
Ключевое слово частной собственности без инициализатора не сгенерирует объявление свойства в излучаемом JavaScript:Компилируется в:
Принимая во внимание, что частные поля всегда генерируют объявление свойства:
Компилируется в (при таргетинге
esnext
):Дальнейшее чтение:
источник
#
Варианты использования: -приватные поляПредисловие:
#
синонимов : -приватный, жесткий приватный, приватный частныйКонфиденциальность во время компиляции и во время выполнения
#
Поля -private обеспечивают конфиденциальность во время компиляции и во время выполнения, что не является "взломанным". Это механизм, предотвращающий доступ к члену вне тела класса любым прямым способом .Безопасное наследование классов
#
-приватные поля получают уникальную область видимости. Иерархии классов могут быть реализованы без случайной перезаписи частных свойств с одинаковыми именами.Компилятор TS, к счастью, выдает ошибку, когда
private
свойства могут быть перезаписаны (см. Этот пример ). Но из-за особенностей функции времени компиляции все еще возможно во время выполнения, учитывая, что ошибки компиляции игнорируются и / или испускается код JS.Внешние библиотеки
Авторы библиотеки могут рефакторировать
#
-приватные идентификаторы, не вызывая серьезных изменений для клиентов. Пользователи библиотеки с другой стороны защищены от доступа к внутренним полям.JS API опускает
#
-приватные поляВстроенные функции и методы JS игнорируют
#
поля -private. Это может привести к более предсказуемому выбору свойств во время выполнения. Примеры:Object.keys
,Object.entries
,JSON.stringify
,for..in
петли и другие ( пример кода , см также Мэтта Bierner в ответ ):Варианты использования:
private
ключевое словоПредисловие:
private
ключевое слово в TS документахДоступ к внутреннему API класса и состоянию (конфиденциальность только во время компиляции)
private
члены класса являются обычными свойствами во время выполнения. Мы можем использовать эту гибкость для доступа к внутреннему API-интерфейсу класса или состоянию извне. Для выполнения проверок компилятором@ts-ignore
могут использоваться такие механизмы, как утверждения типа, динамический доступ к свойствам или другие.Пример с утверждением типа (
as
/<>
) иany
типизированной переменной:TS даже позволяет динамический доступ к свойству
private
члена с помощью escape-люка :Где может иметь смысл частный доступ? (1) модульные тесты, (2) ситуации отладки / регистрации или (3) другие сложные сценарии с внутренними классами проекта (открытый список).
Доступ к внутренним переменным немного противоречив, иначе вы бы не сделали их
private
в первую очередь. В качестве примера, модульные тесты должны быть черными / серыми блоками с закрытыми полями, скрытыми как детали реализации. На практике, тем не менее, могут существовать подходы от случая к случаю.Доступно во всех средах ES
private
Модификаторы TS могут использоваться со всеми целями ES.#
-приватные поля доступны только дляtarget
ES2015
/ES6
или выше. В ES6 +WeakMap
используется внутри как реализация нижнего уровня (см. Здесь ). Собственные#
-приватные поля в настоящее время требуютtarget
esnext
.Согласованность и совместимость
Команды могут использовать рекомендации по кодированию и правилам линтера, чтобы обеспечить использование в
private
качестве единственного модификатора доступа. Это ограничение может помочь в согласованности и избежать путаницы с#
нотацией -private поля обратно совместимым образом.При необходимости свойства параметров (сокращение назначения конструктора) являются ограничителем показа. Их можно использовать только с
private
ключевым словом, и пока нет планов по их реализации для#
полей -private.Другие причины
private
может обеспечить лучшую производительность во время выполнения в некоторых случаях понижения (см. здесь ).private
нотация ключевых слов 😊.Обратите внимание на оба
Оба подхода создают некий номинальный или фирменный тип во время компиляции.
Кроме того, оба разрешают доступ между экземплярами: экземпляр класса
A
может обращаться к закрытым членам другихA
экземпляров:источники
источник