L'encapsulation en JavaScript existe-t-elle?

j'ai une expérience avec le langage de programmation C#, mais je dois aussi travailler avec la JS maintenant, et c'est assez nouveau pour moi.

j'ai essayé de développer une émulation de classe simple dans JS, comme ceci:

http://jsfiddle.net/T74Zm/

function A( inputValue ) {
    this.Init( inputValue );
    this.Print();
}
A.prototype = {
    value: null,
    Init: function( inputValue ) {
        this.value = inputValue;
    },
    Print: function () {
        console.log( this.value );
    }
}

var obj = new A(40);

j'ai essayé d'encapsuler la variable value dans A.prototype , mais il semble être par spécification JavaScript que tous les objets sont disponible.

donc mes questions sont:

1). Comment puis-je faire une encapsulation , qui est très proche des langages statiques avec le support des modificateurs d'accès/OOP?

2). Comment puis-je émuler certains modificateurs d'accès dans JS, comme private par exemple?

1
demandé sur bgusach 2013-11-13 12:19:04

3 réponses

si vous voulez utiliser l'héritage, vous ne pouvez pas (au moins AFAIK). Pour les objets sans chaîne de transmission, vous pouvez cependant utiliser des fermetures pour obtenir exactement le même effet. La question Est de savoir si vous avez vraiment besoin de propriétés pour être complètement privé.

La fermeture de l'approche

vous pouvez exécuter une fonction dont la fermeture contient les variables que vous voulez être privé. Ces variables privées n'appartiennent pas réellement à l'objet, mais sont uniquement accessibles par les méthodes de l'objet. Par exemple:

var getPersonInstance = function (name) {

    // Those are "private" properties
    var myName = name;

    return {
        getName: function () {
            return myName
        },
        setName: function (name) {
            myName = name;
        },
        sayHello = function () {
            alert('hello! my name is ' + myName);
        }
    }    
};

var person = getPersonInstance('Juan');
person.getName(); // Returns Juan
person.myName = 'Don Vito' // This sets the person.myName property, which is not the one in the closure
person.setName('John') // Works
person.sayHello(); // alert hello! my name is John

Vous pouvez le vérifier ici:

http://jsfiddle.net/MLF7v/1 /

si vous vous sentez plus à l'aise avec la notation de la fonction constructeur, vous pouvez faire quelque chose comme ceci:

(non testé)

function Person(name) {
    // Anything that is not attached to this will be private
    var myName = name;


    this.getName = function () { return myName;};
    this.setName = function (newName) {myName = newName;};
    this.sayHello = function () {alert('hey there, my name is' + myName);};
}

ce qui est à peu près le même que ci-dessus, puisque le prototype n'est pas utilisé et les méthodes sont copiés directement dans l'objet.

cependant, l'approche de fermeture sont est la mémoire et le temps, et le pire: ils font usage de variables qui n'appartiennent pas en fait à l'objet avec lequel vous travaillez... C'est un problème "sémantique" important ( cet accessoire m'appartient-il ou non? ) qui fait de l'héritage un mal de tête. La raison pour cela, est que les méthodes des objets étendus soit n'ont pas accès à ce Privé pseudo-propriété (parce qu'ils ne sont pas définis dans la fermeture de superobject), ou avoir accès à une variable privée commune de la "superobject" (la méthode a été définie dans le superobject et donc accéder à la fermeture du superobject). C'est un non-sens.

l'approche " culturelle

À mon humble avis, encapsulation n'empêche personne de jouer avec votre code si il/elle veut vraiment , donc je préfère suivez la philosophie de python "nous sommes tous des adultes" qui consiste à utiliser une convention pour dire "je voudrais que cette propriété ne soit pas utilisée de l'extérieur". Par exemple, je préfixe les propriétés privées avec'_', ce qui signifie qu'elles sont privées, protégées, ou ce que vous voulez, mais restez à l'écart. Et tu ne touches pas ce que tu ne devrais pas toucher.

cette approche, semble d'être le plus simple et le plus efficace, vous permet de travailler avec les chaînes d'héritage, depuis les propriétés sont dans l'objet et non confinées dans la fermeture.

var Person = function (name) {
    this._name = name;
}
Person.prototype.sayHello = function () {...};
Person.prototype.getName = function () {...};
Person.prototype.setName = function () {...};
6
répondu bgusach 2013-11-14 08:27:41

Encapsulation ne signifie pas que l'ordinateur est rigoureusement appliquer que vous n'ACCÉDEZ PAS à quelque chose. Il peut être réalisé simplement par des modules et des classes n'accédant pas aux internes de l'autre. Si votre programme possède cette propriété, alors vous utilisez encapsulation. Ou au moins vous gagnez tous les avantages que l'encapsulation est censée donner-pomme de terre, potahto.

si vous avez besoin d'aide pour cela, vous pouvez utiliser de la documentation et des conventions comme le préfixe underscore. vous savez plus facilement ce qui est interne ou non.

pensez - y-si vous avez fait le remplacement global de" privé "à" public " et recompilé l'un de vos programmes C#, il fonctionnerait exactement le même. Et vous ignorez en quelque sorte que même dans C# one peut accéder privé par .SetAccessible s'ils le veulent. Puisque vous semblez être d'accord avec ça, Quel est le problème?

l'émulation des "privés" par les fermetures vous donne beaucoup plus et des problèmes pires qu'elle solutions que je vais énumérer si vous n'êtes pas déjà convaincu par ce qui précède.

je citerai aussi Martin Fowler pour un argument d'autorité:

contrôle d'Accès ne contrôle pas l'accès

si vous avez un champ qui est privé cela signifie qu'aucune autre classe ne peut obtenir il. Faux! Si vous voulez vraiment vous pouvez renverser le contrôle d'accès mécanismes dans presque toutes les langues. Habituellement, le chemin à travers est via réflexion. La raison en est que les débogueurs et autres outils système souvent besoin de voir des données privées, donc généralement le reflet des interfaces vous permettent de faire cela.

C++ n'a pas ce genre de réflexion, mais là vous pouvez juste utiliser manipulation directe de la mémoire puisque C++ est fondamentalement de la mémoire ouverte.

le point de contrôle d'accès n'est pas d'empêcher l'accès, mais plutôt signalez que la classe préfère garder certaines choses pour elle. Utiliser accès les modificateurs, comme beaucoup de choses dans la programmation, est principalement a propos de la communication.

http://martinfowler.com/bliki/AccessModifier.html#AccessControlDoesNotControlAccess

6
répondu Esailija 2013-11-13 21:18:34

vous pouvez utiliser des fermetures pour encapsuler des variables.

function MyObjectFactory() {
  var obj = {},
    count = 0;

  obj.getCounter = function () {
    return count;
  };

  obj.setCounter = function (val) {
    count = val;
  };

  obj.incrementCounter = function () {
    count++;
  };

  obj.decrementCount = function () {
    count--;
  };

  return obj;  
}

vous pouvez aussi imiter les propriétés getters et setters de manière générique.

function MyOtherObjectFactory() {
  var obj = {}, props = {};

  obj.prop = function (name) {
    return props[name];
  };

  obj.setProp = function (name, val) {
    props[name] = val;
    // call other functions if you'd like
  };


  // or even better, have a single function that works getter and setter regarding the params
  obj.autoProp = function () {
    if (arguments[1]) {
      // setter
      props[arguments[0]] = arguments[1]; // do check first argument is a hashable value
    } else if (arguments[0]) {
      // make sure we have a key
      // getter
      return props[arguments[0]];
    }
  }
}

PS: S'il vous plaît ne réglez pas le prototype directement, il casse la chaîne du prototype.

0
répondu Umur Kontacı 2013-11-13 08:38:56