Есть ли способ сделать «закрытые» переменные (определенные в конструкторе) доступными для методов, определенных прототипами?
TestClass = function(){
var privateField = "hello";
this.nonProtoHello = function(){alert(privateField)};
};
TestClass.prototype.prototypeHello = function(){alert(privateField)};
Это работает:
t.nonProtoHello()
Но это не так:
t.prototypeHello()
Я привык определять свои методы внутри конструктора, но ухожу от этого по нескольким причинам.
javascript
private-members
morgancodes
источник
источник
Ответы:
Нет, это невозможно сделать. По сути, это будет обзор в обратном направлении.
Методы, определенные внутри конструктора, имеют доступ к закрытым переменным, потому что все функции имеют доступ к области, в которой они были определены.
Методы, определенные в прототипе, не определены в области конструктора и не будут иметь доступа к локальным переменным конструктора.
Вы все еще можете иметь закрытые переменные, но если вы хотите, чтобы методы, определенные в прототипе, имели доступ к ним, вы должны определить
this
методы получения и установки для объекта, к которому будут иметь доступ методы прототипа (наряду со всем остальным) . Например:источник
secret
собственностьthis
. JavaScript просто не поддерживает частные переменные с прототипами, так как прототипы связаны с контекстом сайта вызова, а не с контекстом «создания сайта».person.getSecret()
то?Обновление: с ES6, есть лучший способ:
Короче говоря, вы можете использовать новый
Symbol
для создания частных полей.Вот отличное описание: https://curiosity-driven.org/private-properties-in-javascript
Пример:
Для всех современных браузеров с ES5:
Вы можете использовать только замыкания
Самый простой способ конструирования объектов - полностью избежать наследования прототипов. Просто определите закрытые переменные и открытые функции внутри замыкания, и все открытые методы будут иметь частный доступ к переменным.
Или вы можете использовать только прототипы
В JavaScript наследование прототипов - это прежде всего оптимизация . Это позволяет нескольким экземплярам совместно использовать методы-прототипы, а не каждый экземпляр, имеющий свои собственные методы.
Недостаток в том, что
this
это единственное , что отличается каждый раз, когда вызывается прототипная функция.Поэтому любые частные поля должны быть доступны через
this
, что означает, что они будут открытыми. Поэтому мы просто придерживаемся соглашений об именах_private
полей.Не мешайте смешивать крышки с прототипами
Я думаю, что вы не должны смешивать переменные замыкания с методами-прототипами. Вы должны использовать один или другой.
Когда вы используете замыкание для доступа к закрытой переменной, методы-прототипы не могут получить доступ к этой переменной. Таким образом, вы должны выставить закрытие на
this
, что означает, что вы выставляете это публично, так или иначе. При таком подходе очень мало что можно выиграть.Какой мне выбрать?
Для действительно простых объектов просто используйте простой объект с замыканиями.
Если вам нужно наследование прототипа - для наследования, производительности и т. Д. - тогда придерживайтесь соглашения об именовании "_private" и не беспокойтесь о замыканиях.
Я не понимаю, почему разработчики JS так стараются сделать поля по-настоящему приватными.
источник
_private
соглашение об именах по-прежнему является лучшим решением, если вы хотите воспользоваться преимуществами наследования прототипов.Symbol
которая является отличным способом создания частных полей. Вот отличное объяснение: curiosity-driven.org/private-properties-in-javascriptSymbol
в закрытии, которое охватывает весь ваш класс. Таким образом, все методы-прототипы могут использовать Symbol, но он никогда не отображается вне класса.Object.getOwnPropertySymbols
. Так что это только конфиденциальность по неизвестности.toString
. Это ничем не отличается от Java или C # ... закрытые члены по-прежнему доступны через рефлексию, но обычно сильно скрыты. Все это укрепляет мою заключительную мысль: «Я не понимаю, почему разработчики JS так стараются сделать поля по-настоящему приватными».Когда я прочитал это, это звучало как сложная задача, поэтому я решил найти способ. Я придумал CRAAAAZY, но он полностью работает.
Сначала я попытался определить класс в непосредственной функции, чтобы у вас был доступ к некоторым частным свойствам этой функции. Это работает и позволяет вам получать некоторые личные данные, однако, если вы попытаетесь установить личные данные, вы скоро обнаружите, что все объекты будут иметь одинаковое значение.
Существует множество случаев, когда этого было бы достаточно, например, если вы хотите иметь постоянные значения, такие как имена событий, которые будут совместно использоваться экземплярами. Но по сути они действуют как частные статические переменные.
Если вам абсолютно необходим доступ к переменным в закрытом пространстве имен из ваших методов, определенных в прототипе, вы можете попробовать этот шаблон.
Я хотел бы получить отзыв от любого, кто видит ошибку с этим способом сделать это.
источник
i
было добавлено во всех случаях. Так что это не совсем «прозрачно», иi
все еще может быть подделано.см . страницу Дуга Крокфорда на этом . Вы должны сделать это косвенно с чем-то, что может получить доступ к области действия закрытой переменной.
другой пример:
вариант использования:
источник
_set
черезset
? Почему бы просто не назвать этоset
для начала?Я полагаю, что было бы неплохо описать «назначение прототипа в конструкторе» как анти-паттерн Javascript. Подумай об этом. Это слишком рискованно.
То, что вы фактически делаете там при создании второго объекта (т.е. b), переопределяет эту функцию-прототип для всех объектов, которые используют этот прототип. Это эффективно сбросит значение для объекта в вашем примере. Это сработает, если вам нужна общая переменная и если вы случайно создадите все экземпляры объекта, но это кажется слишком рискованным.
В каком-то Javascript, над которым я недавно работал, я обнаружил ошибку, вызванную именно этим анти-паттерном. Он пытался установить обработчик перетаскивания для конкретного создаваемого объекта, но вместо этого делал это для всех экземпляров. Не хорошо.
Решение Дуга Крокфорда - лучшее.
источник
@Kai
Это не сработает. Если вы делаете
тогда
t2.prototypeHello
будет доступ к личному разделу т.@AnglesCrimes
Пример кода работает нормально, но на самом деле он создает «статический» закрытый элемент, общий для всех экземпляров. Возможно, это не то решение, которое искали морганкоды.
До сих пор я не нашел простого и понятного способа сделать это без введения частного хеша и дополнительных функций очистки. Закрытая функция-член может быть смоделирована до определенной степени:
источник
privateFoo
является полностью приватным и, следовательно, невидимым при полученииnew Foo()
. Толькоbar()
публичный метод, который имеет доступ кprivateFoo
. Вы можете использовать тот же механизм для простых переменных и объектов, однако вам всегда следует помнить, чтоprivates
они на самом деле являются статическими и будут общими для всех создаваемых вами объектов.Да, это возможно. Шаблон дизайна PPF только решает это.
PPF обозначает частные функции прототипа. Основной PPF решает эти проблемы:
Для первого, просто:
Это так просто. Например:
...
Прочтите полную историю здесь:
PPF Design Pattern
источник
Вы можете достичь этого, используя Accessor Verification :
Этот пример взят из моего поста о прототипных функциях и личных данных и объясняется там более подробно.
источник
В текущем JavaScript, я абсолютно уверен , что есть один и только один способ иметь личное состояние , доступное из прототипов функций, не добавляя ничего общественность к
this
. Ответ заключается в использовании шаблона «слабая карта».Подводя итог: у
Person
класса есть одна слабая карта, где ключи - это экземпляры Person, а значения - это простые объекты, которые используются для частного хранения.Вот полностью функциональный пример: (игра на http://jsfiddle.net/ScottRippey/BLNVr/ )
Как я уже сказал, это действительно единственный способ достичь всех трех частей.
Однако есть две оговорки. Во-первых, это снижает производительность - каждый раз, когда вы получаете доступ к частным данным, это
O(n)
операция, гдеn
указано количество экземпляров. Так что вы не захотите делать это, если у вас есть большое количество экземпляров. Во-вторых, когда вы закончите с экземпляром, вы должны позвонитьdestroy
; в противном случае экземпляр и данные не будут собираться мусором, что приведет к утечке памяти.И именно поэтому я хотел бы придерживаться моего первоначального ответа «Вы не должны» .
источник
Там более простой способ за счет использования использования
bind
иcall
методов.Установив частные переменные для объекта, вы можете использовать область действия этого объекта.
пример
Этот метод не лишен недостатков. Поскольку контекст контекста фактически переопределяется, у вас нет доступа вне
_private
объекта. Тем не менее, все же невозможно предоставить доступ к области видимости объекта экземпляра. Вы можете передать context (this
) объекта в качестве второго аргументаbind
илиcall
по-прежнему иметь доступ к его открытым значениям в функции prototype.Доступ к общественным ценностям
источник
Попытайся!
источник
caller
, что расширение, зависящее от реализации, не разрешено в строгом режиме.Вот что я придумал.
Основная проблема этой реализации заключается в том, что она переопределяет прототипы в каждом случае.
источник
Есть очень простой способ сделать это
Прототипы JavaScript золотые.
источник
SharedPrivate.prototype
какthis.constructor.prototype
это не большая сделка по - новому getP и SEtP несколько раз ...Я опаздываю на вечеринку, но думаю, что могу внести свой вклад. Вот, проверьте это:
Я называю этот метод шаблоном доступа . Основная идея заключается в том, что у нас есть замыкание , ключ внутри замыкания, и мы создаем частный объект (в конструкторе), к которому можно получить доступ, только если у вас есть ключ .
Если вы заинтересованы, вы можете прочитать больше об этом в моей статье . Используя этот метод, вы можете создавать для каждого объекта свойства, к которым нельзя получить доступ за пределами замыкания. Следовательно, вы можете использовать их в конструкторе или прототипе, но не где-либо еще. Я нигде не видел, чтобы этот метод использовался, но я думаю, что он действительно мощный.
источник
Вы не можете поместить переменные в более высокую область?
источник
Вы также можете попробовать добавить метод не напрямую к прототипу, а к функции конструктора, например так:
источник
Вот кое-что, что я придумал, пытаясь найти самое простое решение для этой проблемы, возможно, это могло бы быть кому-то полезно. Я новичок в javascript, поэтому вполне может быть некоторые проблемы с кодом.
источник
Сегодня я столкнулся с точно таким же вопросом, и после разработки первоклассного ответа Скотта Риппи я нашел очень простое решение (IMHO), которое совместимо с ES5 и эффективно, оно также безопасно для имен (использование _private кажется небезопасным) ,
Протестировано с ringojs и nodejs. Я хочу прочитать ваше мнение.
источник
Как это? Использование частного доступа. Только позволяет получить переменные, но не устанавливать их, зависит от варианта использования.
источник
У меня есть одно решение, но я не уверен, что оно без недостатков.
Чтобы это работало, вы должны использовать следующую структуру:
Вот код:
Как это работает, так это то, что он предоставляет функцию экземпляра «this.getPrivateFields» для доступа к объекту приватных переменных «privateFields», но эта функция будет возвращать только объект «privateFields» внутри определенного основного замыкания (также функции-прототипы, использующие «this.getPrivateFields») «должно быть определено внутри этого замыкания).
Хеш, созданный во время выполнения и трудно угадываемый, используется в качестве параметров, чтобы гарантировать, что даже если getPrivateFields вызывается вне области замыкания, он не будет возвращать объект "privateFields".
Недостатком является то, что мы не можем расширить TestClass большим количеством функций-прототипов за пределами замыкания.
Вот некоторый тестовый код:
РЕДАКТИРОВАТЬ: Используя этот метод, также можно «определить» частные функции.
источник
Играл с этим сегодня, и это было единственное решение, которое я мог найти без использования Symbols. Лучшая вещь об этом - то, что это может фактически быть полностью частным.
Решение основано на домашнем загрузчике модулей, который в основном становится посредником для кеша частного хранилища (используя слабую карту).
источник
Я знаю, что прошло более 1 десятилетия с тех пор, как об этом спросили, но я просто размышлял над этим n-й раз в своей жизни программиста и нашел возможное решение, которое мне пока неизвестно, нравится ли мне еще , Я не видел этой методологии, документированной ранее, поэтому я назову ее «паттерн частного / публичного доллара» или паттерн _ $ / $ .
Концепция использует функцию ClassDefinition, которая возвращает функцию Constructor, которая возвращает объект Interface . Единственный метод интерфейса -
$
это получениеname
аргумента для вызова соответствующей функции в объекте конструктора, любые дополнительные аргументы, переданные послеname
, передаются в вызове.Глобально определена вспомогательная функция
ClassValues
сохраняет все поля в качестве объекта по мере необходимости. Он определяет_$
функцию доступа к нимname
. Это следует за коротким шаблоном get / set, поэтому, еслиvalue
он пройден, он будет использоваться как новое значение переменной.Глобально определенная функция
Interface
принимает объект иValues
объект для возврата_interface
с одной единственной функцией,$
которая исследует,obj
чтобы найти функцию, названную в честь параметра,name
и вызывает ееvalues
как объект области видимости . Переданные дополнительные аргументы$
будут переданы при вызове функции.В приведенном ниже примере
ClassX
присваивается результатClassDefinition
, который являетсяConstructor
функцией.Constructor
может получить любое количество аргументов.Interface
это то, что внешний код получает после вызова конструктора.Нет смысла иметь функции, не являющиеся прототипами
Constructor
, хотя вы можете определить их в теле функции конструктора. Все функции вызываются по общедоступной схеме доллараthis.$("functionName"[, param1[, param2 ...]])
. Доступ к частным значениям осуществляется по схеме частного доллараthis._$("valueName"[, replacingValue]);
. ПосколькуInterface
нет определения для_$
, значения не могут быть доступны для внешних объектов. Поскольку тело каждого прототипа функцииthis
установлено наvalues
объект в функции$
, вы получите исключения, если вызовете функции-братья Constructor напрямую; в _ $ / $ шаблон должен сопровождаться в функции органов прототип тоже. Ниже пример использования.И консольный вывод.
_ $ / $ Шаблон обеспечивает полную конфиденциальность значений в полностью прототипов классов. Я не знаю, буду ли я когда-нибудь этим пользоваться, и не будет ли у него недостатков, но это была хорошая головоломка!
источник
ES6 WeakMaps
Используя простой шаблон, основанный на ES6, WeakMaps позволяет получить закрытые переменные-члены, доступные из функций прототипа .
Более подробное объяснение этого паттерна можно найти здесь
источник
Вам нужно изменить 3 вещи в вашем коде:
var privateField = "hello"
наthis.privateField = "hello"
.privateField
наthis.privateField
.privateField
наthis.privateField
.Окончательный код будет следующим:
источник
this.privateField
не будет частным полем. это доступно снаружи:t.privateField
Вы можете использовать назначение прототипа в определении конструктора.
Переменная будет видима для добавленного метода-прототипа, но все экземпляры функций будут иметь доступ к одной и той же переменной SHARED.
Я надеюсь, что это может быть полезно.
источник