Accès privé à des variables de membre du prototype des fonctions définies par l'
Est-il possible de faire “privé”, les variables (celles qui sont définies dans le constructeur), disponible pour réaliser des prototypes des méthodes définies par l'?
TestClass = function(){
var privateField = "hello";
this.nonProtoHello = function(){alert(privateField)};
};
TestClass.prototype.prototypeHello = function(){alert(privateField)};
Cela fonctionne:
t.nonProtoHello()
Mais ce n'est pas le cas:
t.prototypeHello()
Je suis habitué à la définition de mes méthodes à l'intérieur du constructeur, mais je suis en déplacement à l'écart de cela pour un couple de raisons.
- double possible de Comment créer variable privée accessible au Prototype de la fonction?
- Sauf celui-ci a demandé 2 ans plus tôt....
Vous devez vous connecter pour publier un commentaire.
Non, il n'y a aucun moyen de le faire. Que serait essentiellement portée dans le sens inverse.
Méthodes définies à l'intérieur du constructeur ont accès aux variables privées parce que toutes les fonctions ont accès à de l'étendue dans laquelle ils ont été définis.
Les méthodes définies sur un prototype ne sont pas définis dans le champ d'application du constructeur, et n'auront pas accès à l'constructeur de variables locales.
Vous pouvez toujours avoir des variables privées, mais si vous voulez des méthodes définies dans le prototype d'y avoir accès, vous devez définir des accesseurs et mutateurs sur le
this
objet, dont le prototype des méthodes (avec tout le reste) sera ont accès. Par exemple:secret
une propriété dethis
. JavaScript ne marche tout simplement pas en charge les variables privées avec des prototypes des prototypes sont liés à l'appel-le site et son contexte, non pas la création-site de' contexte.person.getSecret()
alors?Mise à jour: Avec ES6, il ya une meilleure façon:
Longue histoire courte, vous pouvez utiliser la nouvelle
Symbol
pour créer des champs privés.Voici une description: https://curiosity-driven.org/private-properties-in-javascript
Exemple:
Pour tous les navigateurs modernes avec ES5:
Vous pouvez simplement utiliser les Fermetures
La façon la plus simple pour construire des objets est d'éviter les prototypes de l'héritage tout à fait.
Il suffit de définir les variables privées et publiques, des fonctions au sein de la fermeture, et toutes les méthodes publiques auront accès privé pour les variables.
Ou vous pouvez utiliser seulement des Prototypes
En JavaScript, prototypes héritage est principalement une optimisation. Il permet de multiples instances partagent prototype méthodes, plutôt que chaque instance ayant ses propres méthodes.
L'inconvénient est que
this
est le seulement chose de différent à chaque fois une prototypes de fonction est appelée.Par conséquent, tous les champs privés doivent être accessibles par le biais de
this
, ce qui signifie qu'ils vont être public. Nous avons donc simplement s'en tenir à des conventions de nommage pour_private
champs.N'est pas la peine de mélange Fermetures avec des Prototypes
Je pense que vous ne devrait pas mélange de fermeture variables avec le prototype des méthodes. Vous devez utiliser l'un ou l'autre.
Lorsque vous utilisez une fermeture pour accéder à une variable privée, prototype méthodes ne peuvent pas accéder à la variable. Donc, vous avez à exposer la fermeture sur
this
, ce qui signifie que vous êtes de l'exposer publiquement d'une façon ou d'une autre. Il y a très peu de gain avec cette approche.Qui dois-je choisir?
Pour des objets simples, il suffit d'utiliser un objet ordinaire avec des fermetures.
Si vous avez besoin de prototypes héritage -- pour l'héritage, de la performance, etc. -- puis coller avec le "_private" convention de nommage, et ne vous embêtez pas avec des fermetures.
Je ne comprends pas pourquoi les développeurs JS essayer SI dur pour faire des champs de vraiment privé.
_private
convention de nommage est encore la meilleure solution si vous voulez prendre avantage de prototypes à l'héritage.Symbol
, qui est un excellent moyen de créer des champs privés. Voici une bonne explication: curiosity-driven.org/private-properties-in-javascriptSymbol
de référence pour accéder à laSymbol
dans un prototype de fonction? WeakMaps ressemblent plus à des accès privé dans cet exemple que laSymbol
.Symbol
dans une fermeture qui englobe l'ensemble de votre classe. De cette façon, tous les prototypes des méthodes peut utiliser le Symbole, mais il n'est jamais exposé à l'extérieur de la classe.WeakMap
solution est similaire, parce que le WeakMap est maintenu par une fermeture trop, accessible à tous les prototypes des méthodes. Mais le WeakMap plus grand inconvénient est le manque de la collecte des ordures ... vous devez supprimer manuellement les références, ce qui est un énorme inconvénient.Object.getOwnPropertySymbols
. Donc, c'est seulement la vie privée par l'obscurité.toString
. Ce n'est pas différent que Java ou C# ... membres privés sont toujours accessibles via la réflexion, mais sont généralement fortement obscurci. Qui va tout à renforcer mon dernier point, "je ne comprends pas pourquoi les développeurs JS essayer SI dur pour faire des champs de vraiment privé."WeakMap
s résoudre.WeakMap
tel que discuté dans une autre réponse. Vous parlez ES6 natifWeakMap
, qui a de la collecte des ordures, mais si vous avez de l'ES6, puisSymbol
est la meilleure solution.})();
Quand je lis cela, il sonnait comme un défi difficile j'ai donc décidé de trouver un moyen. Ce que je suis venu avec était SUIVANTES mais il fonctionne tout à fait.
Tout d'abord, j'ai essayé la définition de la classe dans une mise en fonction immédiate donc, si vous voulez avoir accès à certaines des propriétés privées de la fonction. Cela fonctionne et vous permet d'obtenir certaines données privées, cependant, si vous essayez de définir les données privées que vous découvrirez bientôt que tous les objets partageront la même valeur.
JS:
Il y a beaucoup de cas où ce serait suffisant comme si vous vouliez ont des valeurs constantes, comme les noms d'événements qui seront partagées entre les instances. Mais, pour l'essentiel, ils agissent comme privé de variables statiques.
Si vous avez absolument besoin d'accéder à des variables dans un espace de noms privé à l'intérieur de vos méthodes définies dans le prototype, vous pouvez essayer ce modèle.
JS:
J'aimerais un retour d'expérience de quelqu'un qui voit une erreur avec cette manière de faire.
delete p[this.i]
mais il ne serait pas automatique.this
avoir un pointeur sur lui-même appelér
eti
seraitivate
de sorte que vous pourriez écrirep[r.ivate]
mais a décidé qu'il était trop stupide. Ou peut-être qu'il n'a pas de travail en dehors du constructeur. De toute façon, si quelqu'un peut trouver un plus beau abréviation dep[this.i]
, ça serait cool.privateNamespace
comme une variable globale!i
a été ajoutée à toutes les instances. Il n'est donc pas totalement "transparent", eti
pourraient encore être modifiées.delete
ne libère pas la mémoire. Il ne déclenche pas de collecte des ordures, à moins que l'supprimé prop est le renvoi définitif.PrivateNamespaceClass
, vous êtes la création d'une nouvelle fermeture de l'instance, qui est la création d'une nouvelle instance de l'intérieur de la fonction et le prototype.this.i
normale de la propriété, vous pouvez utiliserObject.defineProperty
pour en faire un non-inscriptible à la propriété. Ensuite, il serait encore plus sûr.prototype
à tous), comme vous êtes encore en train de créer de nouveaux objets de Fonction pour chaque instance de la classe. Je pense qu'il a aussi l'inconvénient de casserinstanceof
.voir Doug Crockford est sur cette page. Vous devez le faire indirectement avec quelque chose qui peut accéder à la portée de la variable privée.
un autre exemple:
cas d'utilisation:
_set
viaset
? Pourquoi ne pas simplement de nom, ilset
pour commencer?Je suggère qu'elle serait probablement une bonne idée de décrire "avoir un prototype d'affectation dans un constructeur" Javascript anti-modèle. Pensez à ce sujet. Il est trop risqué.
Ce que vous êtes en train de faire, là, sur la création de la deuxième objet (c-b) est en train de redéfinir ce prototype de fonction pour tous les objets qui utilisent ce prototype. Cela aura pour effet de réinitialiser la valeur de l'objet a dans votre exemple. Il ne fonctionnera que si vous voulez une variable partagée et si vous arriver à créer toutes les instances de l'objet à l'avant, mais il est bien trop risqué.
J'ai trouvé un bug dans un peu de Javascript (je travaillais récemment que c'était pour cette raison exacte de l'anti-modèle. Il tente de mettre un glisser-déposer de gestionnaire de la particularité de l'objet en cours de création mais plutôt de le faire pour toutes les instances. Pas bonne.
Doug Crockford solution est la meilleure.
@Kai
Qui ne fonctionne pas. Si vous ne
puis
t2.prototypeHello
accéder t la section privée.@AnglesCrimes
L'exemple de code fonctionne très bien, mais c'est en fait crée une "statique" membre privé partagé par toutes les instances. Il est peut-être pas la solution morgancodes cherché.
Jusqu'à présent, je n'ai pas trouvé facile et propre façon de le faire sans l'introduction d'un privé de hachage et un nettoyage des fonctions. Une fonction membre privée peut être simulé dans une certaine mesure:
privateFoo
est complètement privé et donc invisible lors de l'obtention d'unnew Foo()
. Seulementbar()
est une méthode publique ici, qui a accès àprivateFoo
. Vous pouvez utiliser le même mécanisme pour de simples variables et les objets, cependant, vous devez toujours garder à l'esprit que ceuxprivates
sont en réalité statique et sera partagé par tous les objets que vous créez.Oui, c'est possible. PPF modèle de conception juste résout ce problème.
PPF représente Privé Prototype des Fonctions. De base PPF résout ces problèmes:
Pour la première, tout:
C'est aussi simple que cela. Par exemple:
...
Lisez l'histoire complète ici:
PPF Modèle de Conception
Vous pouvez réellement obtenir à l'aide de Accesseur de Vérification:
Cet exemple vient de mon post sur Prototypes des Fonctions & Données Privées et est expliquée plus en détail.
Dans le courant de JavaScript, je suis assez certain qu'il y a un et un seul moyen d'avoir privé de l'état, accessible à partir de prototype fonctions, sans rien ajouter public à
this
. La réponse est d'utiliser la "faiblesse de la carte" modèle.Pour résumer: Le
Person
de classe a qu'une seule faiblesse de la carte, où les clés sont les instances de la Personne, et les valeurs sont des objets simples qui sont utilisés pour le stockage privé.Ici, c'est un exemple: (jouer à http://jsfiddle.net/ScottRippey/BLNVr/)
Comme je l'ai dit, c'est vraiment la seule façon d'atteindre tous les 3 parties.
Il y a deux mises en garde, cependant. Tout d'abord, les coûts de cette représentation, chaque fois que vous accédez à des données privées, c'est un
O(n)
opération, oùn
est le nombre d'instances. Si vous ne voulez pas le faire si vous avez un grand nombre de cas.Deuxièmement, lorsque vous en avez terminé avec une instance, vous devez appeler
destroy
; sinon, l'instance et les données ne seront pas nettoyés, et vous vous retrouverez avec une fuite de mémoire.Et c'est pourquoi ma réponse originale à cette question, "Vous ne devriez pas", est quelque chose que j'aimerais tenir.
Il y a un moyen plus simple en tirant parti de l'utilisation de
bind
etcall
méthodes.En définissant des variables privées à un objet, vous pouvez l'effet de levier que l'objet de la portée.
Exemple
Cette méthode n'est pas sans inconvénients. Étant donné que la portée contexte est effectivement être remplacé, vous n'avez pas accès à l'extérieur de la
_private
objet. Cependant, il n'est pas impossible cependant de toujours donner l'accès à l'instance de l'objet champ d'application. Vous pouvez passer dans le contexte de l'objet (this
) comme deuxième argumentbind
oucall
pour toujours avoir accès à ses valeurs publiques dans le prototype de la fonction.L'accès public des valeurs
Essayer!
caller
, qui est un dépendant de l'implémentation de l'extension non autorisée dans le strict mode.Voici ce que j'ai trouvé.
le principal problème de cette implémentation est qu'il redéfinit les prototypes de chaque instanciation.
Il y a un moyen très simple de faire ce
JavaScript prototypes sont d'or.
SharedPrivate.prototype
commethis.constructor.prototype
C'est pas une grosse affaire pour redéfinir getP et setP plusieurs fois...Je suis en retard à la fête, mais je pense que je peux contribuer. Ici, check this out:
JS:
J'appelle cette méthode accesseur modèle. L'idée essentielle est que nous avons un fermeture, un clé à l'intérieur de la clôture, et nous créons un objet privé (dans le constructeur) qui ne peut être accessible que si vous avez la clé.
Si vous êtes intéressé, vous pouvez en lire plus à ce sujet dans mon article. En utilisant cette méthode, vous pouvez créer par les propriétés de l'objet qui ne sont pas accessibles à l'extérieur de la clôture. Par conséquent, vous pouvez les utiliser dans un constructeur ou d'un prototype, mais pas n'importe où ailleurs. Je n'ai pas vu cette méthode utilisée n'importe où, mais je pense que c'est vraiment puissant.
Voici quelque chose que je suis venu avec tout en essayant de trouver la plus simple solution de ce problème, peut-être il pourrait être utile à quelqu'un. Je suis nouveau sur le javascript, donc il pourrait bien y avoir quelques problèmes avec le code.
Je me suis confronté exactement la même question aujourd'hui, et après l'élaboration de sur Scott Rippey de première classe de la réponse, j'ai trouvé une solution très simple (à mon humble avis) qui est à la fois compatible avec ES5 et efficace, c'est aussi le nom de clash coffre-fort (à l'aide de _private semble dangereux).
Testé avec ringojs et nodejs. Je suis impatient de lire votre avis.
Comment est-ce? À l'aide d'un accesseur privé. Seulement vous permet d'obtenir les variables mais pas pour les régler, dépend du cas d'utilisation.
J'ai une solution, mais je ne suis pas sûr que c'est sans failles.
Pour que cela fonctionne, vous devez utiliser la structure suivante:
Voici le code:
La façon dont cela fonctionne est qu'il fournit un exemple de la fonction "cette.getPrivateFields" pour accéder à la "privateFields" variables privées de l'objet, mais cette fonction ne retourne que le "privateFields" de l'objet à l'intérieur de la fermeture principale définie (également prototype de fonctions à l'aide de "ce.getPrivateFields" doivent être définies à l'intérieur de cette fermeture).
Un hachage produit au cours de l'exécution et difficile à deviner est utilisé en tant que paramètres pour s'assurer que même si "getPrivateFields" est appelé en dehors de la portée de fermeture ne sera pas de retour l' "privateFields" objet.
L'inconvénient est que l'on ne peut pas s'étendre TestClass avec plus de prototype des fonctions à l'extérieur de la clôture.
Voici un code de test:
EDIT: en Utilisant cette méthode, il est également possible de définir des fonctions privées.
A joué avec cela aujourd'hui et c'était la seule solution que j'ai pu trouver sans l'aide de Symboles. La meilleure chose à ce sujet est qu'il peut effectivement être tous totalement privé.
La solution est basée autour d'un domaine chargeur de module qui, fondamentalement, devient le médiateur pour un stockage privé de cache (à l'aide d'une faiblesse de la carte).
Je sais qu'il a été plus que 1 décennie depuis cet été a été demandé, mais je viens de mettre ma pensée sur ce pour la n-ième fois de ma programmeur de la vie, et a trouvé une solution que je ne sais pas si je suis tout à fait comme encore. Je n'ai pas vu cette méthodologie documentée avant, donc je vais désigner sous le nom de "privé/public dollar pattern" ou _$ /$ motif.
Le concept utilise un ClassDefinition une fonction qui retourne un Constructeur fonction qui renvoie un Interface objet. L'interface est la seule méthode est
$
qui reçoit unname
argument appeler la fonction correspondante dans le constructeur de l'objet, tous les autres arguments passés aprèsname
sont passés dans l'invocation.L'défini globalement fonction d'assistance
ClassValues
magasins de tous les champs dans un objet en tant que de besoin. Il définit la_$
la fonction d'accès parname
. Cela fait suite à une courte get/set modèle donc, sivalue
est adoptée, elle sera utilisée comme nouvelle valeur de la variable.À l'échelle mondiale en fonction définie
Interface
prend un objet et unValues
objet de retour d'un_interface
avec une unique fonction$
qui examineobj
à trouver une fonction nommée d'après le paramètrename
et l'appelle avecvalues
comme le étendue objet. Les arguments supplémentaires passées à$
seront transmis l'appel à la fonction.Dans l'exemple ci-dessous,
ClassX
est attribué à la suite deClassDefinition
, qui est leConstructor
fonction.Constructor
peut recevoir un nombre quelconque d'arguments.Interface
est ce que le code externe obtient après l'appel du constructeur.Il n'y a aucun point en ayant le non-prototypage de fonctions dans
Constructor
, bien que vous pouvez définir dans la fonction constructeur de corps. Toutes les fonctions sont appelées par la public dollar modèlethis.$("functionName"[, param1[, param2 ...]])
. Les valeurs privées sont accessibles avec le privé dollar modèlethis._$("valueName"[, replacingValue]);
. CommeInterface
n'ont pas de définition pour_$
, les valeurs ne peuvent pas être consultées par des objets externes. Depuis chaque prototype de la fonction du corpsthis
est définie à l'values
objet en fonction$
, vous obtiendrez des exceptions si vous appelez le Constructeur de la fratrie directement des fonctions; la _$ /$ motif doit être suivie dans le prototype de la fonction des organes de trop. Ci-dessous d'exemples d'utilisation.Et la sortie de la console.
La _$ /$ motif permet de confidentialité complète de valeurs entièrement prototypes de classes. Je ne sais pas si je vais jamais l'utiliser, ni si elle a des défauts, mais bon, c'était un bon casse-tête!
ES6 WeakMaps
À l'aide d'un modèle simple, basé à ES6 WeakMaps est possible d'obtenir des variables de membre privé, accessible depuis le prototype des fonctions.
JS:
Une explication plus détaillée de ce modèle peut être trouvé ici
Pouvez-vous pas mettre les variables dans une étendue supérieure?
Vous pouvez aussi essayer d'ajouter une méthode pas directement sur le prototype, mais sur la fonction de constructeur comme ceci:
Vous avez besoin de changer 3 choses dans votre code:
var privateField = "hello"
avecthis.privateField = "hello"
.privateField
avecthis.privateField
.privateField
avecthis.privateField
.Le code final serait le suivant:
this.privateField
ne serait pas un champ privé. il est accessible de l'extérieur:t.privateField
Vous pouvez utiliser un prototype d'affectation dans le constructeur de la définition.
La variable sera visible pour le prototype ajout de la méthode, mais de toutes les instances de l'fonctions auront accès à la même variable PARTAGÉE.
J'espère que cela peut être utile.