Можно ли создать частные свойства в классах ES6?
Вот пример. Как я могу запретить доступ instance.property
?
class Something {
constructor(){
this.property = "test";
}
}
var instance = new Something();
console.log(instance.property); //=> "test"
Ответы:
Частные поля (и методы) внедряются в стандарт ECMA . Вы можете начать использовать их сегодня с предустановкой babel 7 и stage 3.
источник
this
в конструкторе перед вызовомsuper()
. И все же Бабель ставит их перед супер.#privateCrap
синтаксиса?#beep() {}
:; и это:async #bzzzt() {}
?Короткий ответ: нет, в классах ES6 нет встроенной поддержки частных свойств.
Но вы можете имитировать это поведение, не присоединяя новые свойства к объекту, а сохраняя их внутри конструктора класса, и используйте методы получения и установки для доступа к скрытым свойствам. Обратите внимание, что методы получения и установки получают переопределение для каждого нового экземпляра класса.
ES6
ES5
источник
class
синтаксиса в первую очередь.getName
иsetName
свойства частными?Чтобы расширить ответ @ loganfsmyth:
Единственные действительно личные данные в JavaScript - это переменные в области видимости. Вы не можете иметь частные свойства в том смысле, что к свойствам обращаются изнутри так же, как к публичным свойствам, но вы можете использовать переменные области действия для хранения личных данных.
Переменные области
Подход здесь состоит в том, чтобы использовать область функции конструктора, которая является частной, для хранения личных данных. Чтобы методы имели доступ к этим частным данным, они также должны быть созданы внутри конструктора, а это означает, что вы воссоздаете их с каждым экземпляром. Это снижение производительности и памяти, но некоторые считают, что это приемлемое ограничение. Наказания можно избежать для методов, которым не нужен доступ к частным данным, добавив их в прототип, как обычно.
Пример:
Scaped WeakMap
WeakMap может использоваться, чтобы избежать производительности предыдущего подхода и потери памяти. WeakMaps связывают данные с объектами (здесь, экземплярами) таким образом, что к ним можно получить доступ только с помощью этого WeakMap. Итак, мы используем метод переменных области видимости для создания приватного WeakMap, а затем используем этот WeakMap для извлечения приватных данных, связанных с
this
. Это быстрее, чем метод переменных области видимости, потому что все ваши экземпляры могут совместно использовать один WeakMap, поэтому вам не нужно пересоздавать методы просто для того, чтобы они получили доступ к своим собственным WeakMaps.Пример:
В этом примере объект используется для использования одного WeakMap для нескольких частных свойств; Вы также можете использовать несколько WeakMaps и использовать их как
age.set(this, 20)
, или написать небольшую оболочку и использовать его по-другому, какprivateProps.set(this, 'age', 0)
.Конфиденциальность этого подхода теоретически может быть нарушена путем вмешательства в глобальный
WeakMap
объект. Тем не менее, весь JavaScript может быть сломан искаженными глобалами. Наш код уже построен на предположении, что этого не происходит.(Этот метод также может быть реализован
Map
, ноWeakMap
лучше, потому чтоMap
он создаст утечки памяти, если вы не будете очень осторожны, и для этого они не отличаются друг от друга.)Полуответ: символы в области видимости
Символ - это тип примитивного значения, которое может служить именем свойства. Вы можете использовать метод переменной области видимости, чтобы создать личный символ, а затем сохранить личные данные в
this[mySymbol]
.Конфиденциальность этого метода может быть нарушена с помощью
Object.getOwnPropertySymbols
, но это несколько неловко сделать.Пример:
Полуответ: Подчеркивает
Старый по умолчанию, просто используйте публичное свойство с префиксом подчеркивания. Хотя это соглашение никоим образом не является частной собственностью, оно достаточно распространено, и оно хорошо справляется с тем, что читатели должны относиться к собственности как к частной, что часто выполняет свою работу. В обмен на это мы получаем подход, который легче читать, легче печатать и быстрее.
Пример:
Вывод
Начиная с ES2017, до сих пор нет идеального способа сделать частную собственность. Различные подходы имеют свои плюсы и минусы. Переменные в области видимости являются действительно приватными; WeakMaps с областями видимости являются очень приватными и более практичными, чем переменные с областями видимости; Символы с определенной областью являются достаточно частными и достаточно практичными; подчеркивания часто бывают достаточно приватными и очень практичными.
источник
instanceof
. Я признаю, что думал об этом подходе как о включенном только для полноты картины и должен был уделить больше внимания тому, на что он действительно способен.Обновление: предложение с более приятным синтаксисом находится в процессе. Вклад приветствуется.
Да, есть - для ограниченного доступа в объектах - ES6 вводит
Symbol
s .Символы уникальны, вы не можете получить доступ к одному извне, кроме как с помощью рефлексии (как рядовые в Java / C #), но любой, кто имеет доступ к символу внутри, может использовать его для доступа к ключу:
источник
Object.getOwnPropertySymbols
? ;)const myPrivateMethod = Math.random(); Something.prototype[''+myPrivateMethod] = function () { ... } new Something()[''+myPrivateMethod]();
Это на самом деле не конфиденциальность, а неясность в смысле традиционного JavaScript. Я бы подумал, что «частный» JavaScript означает использование замыканий для инкапсуляции переменных. Эти переменные, следовательно, не доступны через отражение.private
иprotected
ключевых слов , было бы намного чище , чемSymbol
илиName
. Я предпочитаю точечную запись, а не скобочную. Я хотел бы продолжать использовать точку для личных вещей.this.privateVar
Ответ - нет". Но вы можете создать частный доступ к таким свойствам:
export
ключевого слова.(Предложение о том, что символы можно использовать для обеспечения конфиденциальности, было верным в более ранней версии спецификации ES6, но это уже не так: https://mail.mozilla.org/pipermail/es-discuss/2014-January/035604. html и https://stackoverflow.com/a/22280202/1282216 . Более подробное обсуждение символов и конфиденциальности см. по адресу : https://curiosity-driven.org/private-properties-in-javascript ).
источник
Единственный способ получить истинную конфиденциальность в JS - это ограничить область действия, поэтому нет способа иметь свойство, являющееся членом,
this
которое будет доступно только внутри компонента. Лучший способ хранить действительно личные данные в ES6 - это WeakMap.Очевидно, что это, вероятно, медленно и определенно некрасиво, но обеспечивает конфиденциальность.
Имейте в виду, что ДАЖЕ ЭТО не идеально, потому что Javascript настолько динамичен. Кто-то еще мог сделать
чтобы ловить значения по мере их хранения, поэтому, если вы хотите быть очень осторожными, вам нужно будет захватить локальную ссылку
.set
и.get
использовать ее явно, вместо того чтобы полагаться на перезаписываемый прототип.источник
get
до одного на метод (напримерconst _ = privates.get(this); console.log(_.privateProp1);
).const myObj = new SomeClass(); console.log(privateProp1.get(myObj)) // "I am Private1"
это означает, что ваша собственность частная или нет?Для дальнейшего ознакомления с другими пользователями я слышу, что рекомендуется использовать WeakMaps для хранения личных данных.
Вот более понятный рабочий пример:
источник
Зависит от того, кого ты спрашиваешь :-)
Нет
private
Модификатор свойства не входят в минимальных классах МАКСИМАЛЬНО предложение , которое , кажется, сделал это в текущий проект .Тем не менее, может существовать поддержка частных имен , которая допускает закрытые свойства - и они, вероятно, также могут использоваться в определениях классов.
источник
Использование модулей ES6 (первоначально предложенных @ d13) хорошо работает для меня. Он не полностью имитирует частные свойства, но, по крайней мере, вы можете быть уверены, что свойства, которые должны быть частными, не будут вытекать за пределы вашего класса. Вот пример:
something.js
Тогда код потребления может выглядеть так:
Обновление (важно):
Как отметил @DanyalAytekin в комментариях, эти частные свойства являются статическими, поэтому имеют глобальный охват. Они будут хорошо работать при работе с синглетонами, но нужно соблюдать осторожность для временных объектов. Расширяя пример выше:
источник
private static
.a.say(); // a
должно бытьb.say(); // b
let _message = null
кстати, не так круто, когда вызывал конструктор несколько раз, он все испортил.Завершение @ d13 и комментарии @ johnny-oshika и @DanyalAytekin:
Я предполагаю, что в примере, представленном @ johnny-oshika, мы могли бы использовать обычные функции вместо функций стрелок, а затем
.bind
их с текущим объектом и_privates
объектом в качестве параметра карри:something.js
main.js
Преимущества, которые я могу придумать:
_greet
и_updateMessage
действовать как приватные методы, пока у нас нетexport
ссылок)_privates
объектНекоторые недостатки, которые я могу вспомнить:
Работающий фрагмент можно найти здесь: http://www.webpackbin.com/NJgI5J8lZ
источник
Да - вы можете создать инкапсулированное свойство , но это не было сделано с помощью модификаторов доступа (public | private), по крайней мере, с ES6.
Вот простой пример того, как это можно сделать с ES6:
1 Создайте класс, используя слово класса
2 Внутри его конструктора объявите блочную переменную, используя let OR const зарезервированные слова ->, так как они являются областью видимости блока, к ним нельзя получить доступ извне (инкапсулировано)
3 Чтобы разрешить некоторый контроль доступа (setters | getters) к этим переменным, вы можете объявить метод экземпляра внутри его конструктора, используя:
this.methodName=function(){}
синтаксисТеперь давайте проверим это:
источник
new Something();
потому что ваши методы объявлены в конструкторе для доступа к этим частные переменные. Это может привести к значительному потреблению памяти, если вы создаете много экземпляров своего класса, поэтому проблемы с производительностью. Методы должны были быть объявлены вне области конструктора. Мой комментарий был скорее объяснением ваших недостатков, чем критикой.Другой подход к «частному»
Вместо того чтобы бороться с тем фактом, что частная видимость в настоящее время недоступна в ES6, я решил использовать более практичный подход, который прекрасно работает, если ваша IDE поддерживает JSDoc (например, Webstorm). Идея состоит в том, чтобы использовать
@private
тег . Что касается разработки, IDE не позволит вам получить доступ к любому частному члену вне его класса. Для меня это очень хорошо работает, и это действительно полезно для сокрытия внутренних методов, поэтому функция автозаполнения показывает мне, что на самом деле хотел показать класс. Вот пример:источник
@private
комментарий не может помешать этому, это только функция для создания документации, и вы IDE.WeakMap
Object.getOwnPropertySymbols
)Сначала определим функцию для переноса WeakMap:
Затем создайте ссылку за пределами вашего класса:
Примечание: класс не поддерживается IE11, но в примере он выглядит чище.
источник
О, так много экзотических решений! Меня обычно не волнует конфиденциальность, поэтому я использую «псевдо-конфиденциальность», как здесь сказано . Но если все равно (если для этого есть особые требования), я использую что-то вроде этого:
Еще одна возможная реализация функции (конструктор)
Job
:источник
Лично мне нравится предложение оператора связывания,
::
а затем я бы объединил его с упомянутым решением @ d13, но сейчас придерживаюсь ответа @ d13, где вы используетеexport
ключевое слово для своего класса и помещаете частные функции в модуль.есть еще одно жесткое решение, которое не было упомянуто здесь, а это более функциональный подход, который позволил бы иметь все частные методы / методы в классе.
Private.js
Test.js
комментарии по этому вопросу будут оценены.
источник
Я наткнулся на этот пост, когда искал лучшую практику для «личных данных для классов». Было упомянуто, что у некоторых шаблонов будут проблемы с производительностью.
Я собрал несколько тестов jsperf, основанных на 4 основных шаблонах из онлайн-книги «Исследование ES6»:
http://exploringjs.com/es6/ch_classes.html#sec_private-data-for-classes
Тесты можно найти здесь:
https://jsperf.com/private-data-for-classes
В Chrome 63.0.3239 / Mac OS X 10.11.6 наиболее эффективными шаблонами были «Личные данные через среды конструктора» и «Личные данные через соглашение об именах». Для меня Safari показала хорошие результаты для WeakMap, но Chrome не так хорошо.
Я не знаю влияния на память, но шаблон для «среды конструктора», который некоторые предупреждали, будет проблемой производительности, был очень производительным.
4 основных шаблона:
Частные данные в среде конструктора
Частные данные в среде конструктора 2
Личные данные через соглашение об именах
Личные данные через WeakMaps
Личные данные через символы
источник
Я считаю, что можно получить «лучшее из обоих миров», используя замыкания внутри конструкторов. Есть два варианта:
Все данные члены являются частными
Некоторые участники являются частными
ПРИМЕЧАНИЕ: это по общему признанию некрасиво. Если вы знаете лучшее решение, отредактируйте этот ответ.
источник
На самом деле это возможно с помощью символов и прокси. Вы используете символы в области видимости класса и устанавливаете две ловушки в прокси: одну для прототипа класса, чтобы Reflect.ownKeys (instance) или Object.getOwnPropertySymbols не передавали ваши символы, а другая - для самого конструктора. поэтому, когда
new ClassName(attrs)
вызывается, возвращаемый экземпляр будет перехвачен и заблокирован символы собственных свойств. Вот код:Reflect.ownKeys()
работает так:Object.getOwnPropertyNames(myObj).concat(Object.getOwnPropertySymbols(myObj))
вот почему нам нужна ловушка для этих объектов.источник
Даже Typescript не может этого сделать. Из их документации :
Но переносится на их площадку это дает:
Поэтому их «личное» ключевое слово неэффективно.
источник
Пришел очень поздно на эту вечеринку, но я задал вопрос OP в поиске, так что ... Да, вы можете иметь частные свойства, заключив объявление класса в закрытие
Существует пример того, как у меня есть частные методы в этом коде . В приведенном ниже фрагменте класс Subscribeable имеет две «приватные» функции
process
иprocessCallbacks
. Любые свойства могут быть добавлены таким образом, и они остаются закрытыми благодаря использованию замыкания. Конфиденциальность IMO является редкой необходимостью, если проблемы хорошо разделены, и Javascript не нужно раздуваться, добавляя больше синтаксиса, когда замыкание аккуратно делает свою работу.Мне нравится этот подход, потому что он хорошо разделяет проблемы и сохраняет конфиденциальность. Единственным недостатком является необходимость использовать «я» (или что-то подобное), чтобы ссылаться на «это» в частном контенте.
источник
Я думаю, что ответ Бенджамина, вероятно, лучший в большинстве случаев, пока язык не поддерживает явно частные переменные.
Однако, если по какой-то причине вам нужно предотвратить доступ с
Object.getOwnPropertySymbols()
помощью метода, который я рассмотрел, используется присоединение уникального, неконфигурируемого, не перечисляемого, недоступного для записи свойства, которое можно использовать в качестве идентификатора свойства для каждого объекта в конструкции. (например, уникальноеSymbol
, если у вас еще нет другого уникального свойства, такого какid
). Затем просто сохраните карту «частных» переменных каждого объекта, используя этот идентификатор.Потенциальным преимуществом этого подхода по сравнению с использованием
WeakMap
является более быстрое время доступа, если производительность становится проблемой.источник
destroy()
метод, который должен вызываться кодом использования всякий раз, когда требуется удалить объект.Да, вполне может, и довольно легко тоже. Это делается путем предоставления ваших личных переменных и функций путем возврата графа прототипа объекта в конструктор. В этом нет ничего нового, но потратьте немного js foo, чтобы понять его элегантность. Этот способ не использует глобальные области видимости или слабые карты. Это форма отражения, встроенная в язык. В зависимости от того, как вы используете это; Можно либо вызвать исключение, которое прерывает стек вызовов, либо похоронить исключение как
undefined
. Это показано ниже, и вы можете узнать больше об этих функциях здесьисточник
источник
console.log(instance.property)
должен бросить или дать вам неопределенный, а не вернуть вам «тест».Еще один способ, похожий на последние два опубликованных
источник
Большинство ответов либо говорят, что это невозможно, либо требуют использования WeakMap или Symbol, которые являются функциями ES6, для которых, вероятно, потребуются полифилы. Однако есть и другой способ! Проверьте это:
Я называю этот метод Accessor Pattern . Основная идея заключается в том, что у нас есть замыкание , ключ внутри замыкания, и мы создаем частный объект (в конструкторе), к которому можно получить доступ только при наличии ключа .
Если вы заинтересованы, вы можете прочитать больше об этом в моей статье . Используя этот метод, вы можете создавать для каждого объекта свойства, к которым нельзя получить доступ за пределами замыкания. Следовательно, вы можете использовать их в конструкторе или прототипе, но не где-либо еще. Я нигде не видел, чтобы этот метод использовался, но я думаю, что он действительно мощный.
источник
Посмотрите этот ответ для чистого и простого «классного» решения с приватным и общедоступным интерфейсом и поддержкой композиции.
источник
Я нашел очень простое решение, просто используйте
Object.freeze()
. Конечно, проблема в том, что вы не можете ничего добавить к объекту позже.источник
setName(name) { this.name = name; }
Я использую этот шаблон, и он всегда работал для меня
источник
На самом деле это возможно.
1. Сначала создайте класс и в конструкторе верните вызванную
_public
функцию.2. В вызываемой
_public
функции передатьthis
ссылку (чтобы получить доступ ко всем закрытым методам и реквизитам) и все аргументы изconstructor
(которые будут переданы вnew Names()
)3. В области
_public
действия функции также естьNames
класс с доступом кthis
(_this ) ссылка частногоNames
классаисточник
Вы можете попробовать это https://www.npmjs.com/package/private-members
Этот пакет сохранит участников по экземпляру.
источник