192 votes

JavaScript - pour accéder aux variables de membre privé de fonctions définies par le prototype

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)};

Ceci fonctionne:

t.nonProtoHello()

mais ce n'est pas:

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.

merci!

-Morgan


Grâce sktrdie,

Qui fonctionne, il serait agréable de ne pas avoir à créer de la ce.accessPrivateField. Si mon "bonjour" de la fonction est définie à l'intérieur du constructeur, privateField est dans le champ d'application de la chaîne de la fonction, afin que je puisse traiter privateField comme je l'aurais un domaine privé en java. C'est un peu plus lourd à définir des accesseurs (ce.accessPrivateField), et puis, privateField n'est pas vraiment privé. Je sais que javascript n'est pas java, mais j'ai comme java!

-Morgan

197voto

Triptych Points 70247

Non, il n'y a aucun moyen de le faire. Que serait essentiellement portée dans le sens inverse.

Les 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 l' this de l'objet, dont le prototype des méthodes (avec tout le reste) va avoir accès. Par exemple:

function Person(name, secret)
{
    // public
    this.name = name;

    // private
    var secret = secret;

    // public methods have access to private members
    this.setSecret = function(s) {
        secret = s;
    }

    this.getSecret = function() {
        return secret;
    }
}

// Must use getters/setters 
Person.prototype.spillSecret = function() { alert(this.getSecret()); };

64voto

Scott Rippey Points 6921

Je pense que vous ne devriez pas mélanger la fermeture des variables avec des prototypes de méthodes. Vous devez utiliser l'un ou l'autre.

Bien que de toute évidence, vous comprenez déjà des fermetures, des variables privées, et des prototypes de l'héritage, je tiens à les décrire pour illustrer mon point.

Les fermetures Privé et Public

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.

Prototype pour le Privé et le Public

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 l' this est la seule chose qui est différente à chaque fois une prototypes de fonction est appelée.
Par conséquent, tous les champs privés doivent être accessibles par le biais this, ce qui signifie qu'ils vont être public. Nous avons donc simplement s'en tenir à des conventions de nommage pour _private champs.

À l'aide de Fermetures pour les particuliers et prototype pour le Public

Lorsque vous utilisez une fermeture à créer une variable privée, vous ne pouvez pas accéder à partir d'un prototypes méthode , sauf si elle est exposée à travers l' this variable. La plupart des solutions, par conséquent, seulement exposer la variable par une méthode, ce qui signifie que vous êtes de l'exposer publiquement d'une façon ou d'une autre.

Alors, lequel choisir?

Je pense à l'aide de prototypes de l'héritage qui fait le plus de sens, rend le débogage plus facile, assure la transparence, peut améliorer les performances, et donc c'est ce que j'utilise habituellement.
Stick à des conventions pour l' _private champs et tout va très bien.
Et je ne comprends pas pourquoi les développeurs JS essayer SI dur pour faire des champs de vraiment privé.

31voto

Mims H. Wright Points 1979

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.

var SharedPrivateClass = (function(){ // use immediate function
    // our private data
    var private = "Default";

    // create the constructor
    function SharedPrivateClass () {}

    // add to the prototype
    SharedPrivateClass.prototype.getPrivate = function () {
        // It has access to private vars from the immediate function!
        return private;
    }

    SharedPrivateClass.prototype.setPrivate = function (value) {
        private = value;
    }

    return SharedPrivateClass;
})();

var a = new SharedPrivateClass();
console.log("a:", a.getPrivate()); // "a: Default"

var b = new SharedPrivateClass();
console.log("b:", b.getPrivate()); // "b: Default"

a.setPrivate("foo"); // a Sets private to 'foo'
console.log("a:", a.getPrivate()); // "a: foo"
console.log("b:", b.getPrivate()); // oh no, b.getPrivate() is 'foo'!

console.log(a.hasOwnProperty("getPrivate")); // false. belongs to the prototype
console.log(a.private); // undefined

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.

var PrivateNamespaceClass = (function(){  // immediate function
    var instance = 0, // counts the number of instances
        defaultName = "Default Name",  
        p = []; // an array of private objects

    // careate the constructor
    function PrivateNamespaceClass () {
        // Increment the instance count and save it to the instance. 
        // This will become your key to your private space.
        this.i = instance++; 

        // Create a new object in the private space.
        p[this.i] = {};
        // Define properties or methods in the private space.
        p[this.i].name = defaultName;

        console.log("New instance " + this.i);        
    }
    PrivateNamespaceClass.prototype.getPrivateName = function () {
        // It has access to the private space and it's children!
        return p[this.i].name;
    }
    PrivateNamespaceClass.prototype.setPrivateName = function (value) {
        // Because you use the instance number assigned to the object (this.i)
        // as a key, the values set will not change in other instances.
        p[this.i].name = value;
        return "Set " + p[this.i].name;
    }

    return PrivateNamespaceClass;
})();

var a = new PrivateNamespaceClass();
console.log(a.getPrivateName()); // Default Name

var b = new PrivateNamespaceClass();
console.log(b.getPrivateName()); // Default Name

console.log(a.setPrivateName("A"));
console.log(b.setPrivateName("B"));
console.log(a.getPrivateName()); // A
console.log(b.getPrivateName()); // B

console.log(a.privateNamespace); // undefined

J'aimerais un retour d'expérience de quelqu'un qui voit une erreur avec cette manière de faire.

18voto

Jason S Points 58434

Voir la page de Doug Crockford là-dessus. 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 :

15voto

Lance Ewing Points 101

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.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X