45 votes

Classes JavaScript

Je comprends le code JavaScript de base des pseudo-classes:

function Foo(bar) {
    this._bar = bar;
}

Foo.prototype.getBar = function() {
    return this._bar;
};

var foo = new Foo('bar');
alert(foo.getBar()); // 'bar'
alert(foo._bar); // 'bar'

Je comprends également que le motif de module, qui peut émuler l'encapsulation:

var Foo = (function() {
    var _bar;

    return {
        getBar: function() {
            return _bar;
        },
        setBar: function(bar) {
            _bar = bar;
        }
    };
})();

Foo.setBar('bar');
alert(Foo.getBar()); // 'bar'
alert(Foo._bar); // undefined

Mais il y a de l'onu-programmation orientée objet-comme les propriétés de ces deux modèles. Le premier n'a pas de fournir de l'encapsulation. Ce dernier ne fournit pas d'instanciation. Les deux modèles peuvent être modifiés à l'appui de pseudo-héritage.

Ce que je voudrais savoir c'est si il n'y a aucun motif qui permet de:

  • L'héritage
  • L'Encapsulation (soutien pour le "privé" propriétés/méthodes)
  • L'instanciation (peut avoir plusieurs instances de la "classe", chacun avec son propre état)

72voto

gion_13 Points 15594

ce :

var Foo = (function() {
    // "private" variables 
    var _bar;

    // constructor
    function Foo(){};

    // add the methods to the prototype so that all of the 
    // Foo instances can access the private static
    Foo.prototype.getBar = function() {
        return _bar;
    };
    Foo.prototype.setBar = function(bar) {
        _bar = bar;
    };

    return Foo;
})();

Et maintenant, nous avons l'instanciation, l'encapsulation et l'héritage.
Mais, il y a toujours un problème. L' private variable static parce qu'il est partagé entre toutes les instances de l' Foo. Démonstration rapide :

var a = new Foo();
var b = new Foo();
a.setBar('a');
b.setBar('b');
alert(a.getBar()); // alerts 'b' :(    

Une meilleure approche pourrait être à l'aide de conventions pour les variables privées : toute variable privée doit commencer par un caractère de soulignement. Cette convention est bien connu et largement utilisé, de sorte que quand un autre programmeur utilise ou modifie votre code et voit une variable de départ avec un trait de soulignement, qu'il sache que c'est privé, pour un usage interne seulement et il ne sera pas le modifier.
Voici la réécriture à l'aide de cette convention :

var Foo = (function() {
    // constructor
    function Foo(){
        this._bar = "some value";
    };

    // add the methods to the prototype so that all of the 
    // Foo instances can access the private static
    Foo.prototype.getStaticBar = function() {
        return this._bar;
    };
    Foo.prototype.setStaticBar = function(bar) {
        this._bar = bar;
    };

    return Foo;
})();

Maintenant, nous avons l'instanciation, héritage, mais nous avons perdu notre encapsulation en faveur de conventions :

var a = new Foo();
var b = new Foo();
a.setBar('a');
b.setBar('b');
alert(a.getBar()); // alerts 'a' :) 
alert(b.getBar()); // alerts 'b' :) 

mais le privé vars sont accessibles :

delete a._bar;
b._bar = null;
alert(a.getBar()); // alerts undefined :(
alert(b.getBar()); // alerts null :(

7voto

3voto

user1701047 Points 331

Javascript est certainement la POO. Vous avez toujours le polymorphisme, cependant, vous avez à sacrifier soit l'encapsulation ou d'instanciation qui est le problème que vous avez couru dans.

Essayez ceci pour juste la brosse sur vos options. http://www.webmonkey.com/2010/02/make_oop_classes_in_javascript/ Aussi une question aussi ancienne que j'avais mis en signet: Est JavaScript orienté objet?

0voto

brejep Points 66

Je pensais à ce sujet particulier récemment et aux limites des différentes approches. La meilleure solution que j'ai pu trouver est celle ci-dessous.

Il semble résoudre les problèmes d’héritage, d’instanciation et d’écapsulation (du moins à partir des tests effectués sur Google Chrome v.24) bien qu’il ait probablement un coût d’utilisation de la mémoire.

 function ParentClass(instanceProperty) {
  // private
  var _super = Object.create(null),
      privateProperty = "private " + instanceProperty;
  // public
  var api = Object.create(_super);
  api.constructor = this.constructor;
  api.publicMethod = function() {
     console.log( "publicMethod on ParentClass" );
     console.log( privateProperty );
  };
  api.publicMethod2 = function() {
     console.log( "publicMethod2 on ParentClass" );
     console.log( privateProperty );
  };
  return api;
}

function SubClass(instanceProperty) {
    // private
    var _super = ParentClass.call( this, instanceProperty ),
        privateProperty = "private sub " + instanceProperty;
    // public
    var api = Object.create(_super);
    api.constructor = this.constructor;
    api.publicMethod = function() {
       _super.publicMethod.call(this); // call method on ParentClass
        console.log( "publicMethod on SubClass" );
        console.log( privateProperty );
    }
    return api;
}

var par1 = new ParentClass(0),
    par2 = new ParentClass(1),
    sub1 = new SubClass(2),
    sub2 = new SubClass(3);

par1.publicMethod();
par2.publicMethod();
sub1.publicMethod();
sub2.publicMethod();
par1.publicMethod2();
par2.publicMethod2();
sub1.publicMethod2();
sub2.publicMethod2();
 

0voto

Un problème avec beaucoup de JS classes là, c'est qu'ils ne sont pas sûr de leurs champs et de méthodes qui signifie que n'importe qui de l'utiliser risquez de remplacer une méthode. Par exemple le code:

function Class()
{
  var name="Luis";
  var lName="Potter";
}
Class.prototype.changeName=function(){
  this.name="BOSS";
  console.log(this.name);
};

var test= new Class();
console.log(test.name);
test.name="ugly";
console.log(test.name);
test.changeName();
test.changeName=function(){console.log("replaced")};
test.changeName();
test.changeName();

sortie:

ugly
BOSS
replaced 
replaced 

Comme vous pouvez le voir le changeName fonction est surchargée. Le code suivant les méthodes de la classe et les champs, et les getters et setters serait utilisé pour accéder à leur rendre cela plus d'un "régulier" class trouvé dans d'autres langues.

function Class()
{
  var name="Luis";
  var lName="Potter";
  function getName(){console.log("called getter"); return name;};
  function setName(val){console.log("called setter"); name = val};
  function getLName(){return lName};
  function setLName(val){lName = val;};
   Object.defineProperties(this, {name:{get:getName, set:setName, enumerable:true, configurable:false},
     lastName:{get:getLName, set:setLName, enumerable:true, configurable:false}
   });
}
Class.prototype.changeName=function(){
  this.name="BOSS";
};   
Object.defineProperty(Class.prototype, "changeName", {writable:false, configurable:false});

var test= new Class();
console.log(test.name);
test.name="ugly";
console.log(test.name);
test.changeName();
test.changeName=function(){console.log("replaced")};
test.changeName();
test.changeName();

Ce sorties:

called getter
Luis
called setter 
called getter 
ugly 
called setter 
called setter 
called setter 

Maintenant, votre les méthodes de la classe ne peut pas être remplacé par des valeurs aléatoires ou des fonctions et du code dans les getters et setters toujours exécuter lors de la tentative de lecture ou d'écriture sur le terrain.

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