115 votes

Comment créer une classe de base abstraite en JavaScript ?

Est-il possible de simuler une classe de base abstraite en JavaScript ? Quelle est la manière la plus élégante de le faire ?

Disons que je veux faire quelque chose comme : -

var cat = new Animal('cat');
var dog = new Animal('dog');

cat.say();
dog.say();

Il devrait sortir : "aboyer", "miauler

137voto

Jordão Points 29221

Une façon simple de créer une classe abstraite est la suivante :

/**
 @constructor
 @abstract
 */
var Animal = function() {
    if (this.constructor === Animal) {
      throw new Error("Can't instantiate abstract class!");
    }
    // Animal initialization...
};

/**
 @abstract
 */
Animal.prototype.say = function() {
    throw new Error("Abstract method!");
}

El Animal "classe" et le say sont abstraits.

La création d'une instance entraînerait une erreur :

new Animal(); // throws

C'est ainsi que vous en "héritez" :

var Cat = function() {
    Animal.apply(this, arguments);
    // Cat initialization...
};
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;

Cat.prototype.say = function() {
    console.log('meow');
}

Dog ressemble à ça.

Et c'est ainsi que se déroule votre scénario :

var cat = new Cat();
var dog = new Dog();

cat.say();
dog.say();

Violon aquí (regardez la sortie de la console).

0 votes

Pouvez-vous m'expliquer ligne par ligne, si vous le voulez bien, car je suis novice en matière de POO. Merci !

2 votes

@undefined : pour le comprendre je vous suggère de regarder l'héritage prototypique en Javascript : este est un bon guide.

0 votes

Merci pour la réponse. Je vais consulter le lien.

27voto

some Points 18965

Voulez-vous dire quelque chose comme ça :

function Animal() {
  //Initialization for all Animals
}

//Function and properties shared by all instances of Animal
Animal.prototype.init=function(name){
  this.name=name;
}
Animal.prototype.say=function(){
    alert(this.name + " who is a " + this.type + " says " + this.whattosay);
}
Animal.prototype.type="unknown";

function Cat(name) {
    this.init(name);

    //Make a cat somewhat unique
    var s="";
    for (var i=Math.ceil(Math.random()*7); i>=0; --i) s+="e";
    this.whattosay="Me" + s +"ow";
}
//Function and properties shared by all instances of Cat    
Cat.prototype=new Animal();
Cat.prototype.type="cat";
Cat.prototype.whattosay="meow";

function Dog() {
    //Call init with same arguments as Dog was called with
    this.init.apply(this,arguments);
}

Dog.prototype=new Animal();
Dog.prototype.type="Dog";
Dog.prototype.whattosay="bark";
//Override say.
Dog.prototype.say = function() {
        this.openMouth();
        //Call the original with the exact same arguments
        Animal.prototype.say.apply(this,arguments);
        //or with other arguments
        //Animal.prototype.say.call(this,"some","other","arguments");
        this.closeMouth();
}

Dog.prototype.openMouth=function() {
   //Code
}
Dog.prototype.closeMouth=function() {
   //Code
}

var dog = new Dog("Fido");
var cat1 = new Cat("Dash");
var cat2 = new Cat("Dot");

dog.say(); // Fido the Dog says bark
cat1.say(); //Dash the Cat says M[e]+ow
cat2.say(); //Dot the Cat says M[e]+ow

alert(cat instanceof Cat) // True
alert(cat instanceof Dog) // False
alert(cat instanceof Animal) // True

0 votes

Peut-être l'ai-je manqué. Où la classe de base (Animal) est-elle abstraite ?

6 votes

@HairOfTheDog Oui, vous avez oublié que la réponse à cette question a été donnée il y a environ cinq ans, qu'à l'époque javascript n'avait pas de classes abstraites, que la question portait sur un moyen de simuler il ( whattosay n'est pas défini dans animal ), et que cette réponse demande clairement si la réponse proposée correspond à ce que le questionneur recherchait. Elle ne prétend pas donner une solution pour les classes abstraites en javascript. L'auteur de la question n'a pas pris la peine de me répondre ou de répondre à quelqu'un d'autre, donc je n'ai aucune idée si cela a fonctionné pour lui. Je suis désolé si la réponse proposée il y a cinq ans à la question de quelqu'un d'autre n'a pas fonctionné pour vous.

15voto

Ian Oxley Points 5659

Vous pouvez consulter le livre Base Class de Dean Edwards : http://dean.edwards.name/weblog/2006/03/base/

Sinon, il y a cet exemple/article de Douglas Crockford sur l'héritage classique en JavaScript : http://www.crockford.com/javascript/inheritance.html

13 votes

En ce qui concerne le lien avec Crockford, c'est un tas de conneries. Il a ajouté une note à la fin de cet article : "Je considère maintenant que mes premières tentatives pour soutenir le modèle classique en JavaScript étaient une erreur."

11voto

bobince Points 270740

Est-il possible de simuler une classe de base abstraite en JavaScript ?

Certainement. Il y a environ un millier de façons d'implémenter des systèmes classe/instance en JavaScript. En voici une :

// Classes magic. Define a new class with var C= Object.subclass(isabstract),
// add class members to C.prototype,
// provide optional C.prototype._init() method to initialise from constructor args,
// call base class methods using Base.prototype.call(this, ...).
//
Function.prototype.subclass= function(isabstract) {
    if (isabstract) {
        var c= new Function(
            'if (arguments[0]!==Function.prototype.subclass.FLAG) throw(\'Abstract class may not be constructed\'); '
        );
    } else {
        var c= new Function(
            'if (!(this instanceof arguments.callee)) throw(\'Constructor called without "new"\'); '+
            'if (arguments[0]!==Function.prototype.subclass.FLAG && this._init) this._init.apply(this, arguments); '
        );
    }
    if (this!==Object)
        c.prototype= new this(Function.prototype.subclass.FLAG);
    return c;
}
Function.prototype.subclass.FLAG= new Object();

var cat = new Animal('cat') ;

Ce n'est pas vraiment une classe de base abstraite, bien sûr. Voulez-vous dire quelque chose comme :

var Animal= Object.subclass(true); // is abstract
Animal.prototype.say= function() {
    window.alert(this._noise);
};

// concrete classes
var Cat= Animal.subclass();
Cat.prototype._noise= 'meow';
var Dog= Animal.subclass();
Dog.prototype._noise= 'bark';

// usage
var mycat= new Cat();
mycat.say(); // meow!
var mygiraffe= new Animal(); // error!

0 votes

Pourquoi utiliser la nouvelle construction maléfique Function(...) ? Ne serait-il pas préférable d'utiliser var c = function () { ... } ; ne serait-il pas mieux ?

2 votes

"var c= function() {...}" créerait une fermeture sur tout ce qui se trouve dans subclass() ou tout autre scope contenant. Ce n'est probablement pas important, mais je voulais éviter les scopes parents potentiellement indésirables ; le constructeur Function() en texte pur évite les fermetures.

10voto

Leven Points 355
Animal = function () { throw "abstract class!" }
Animal.prototype.name = "This animal";
Animal.prototype.sound = "...";
Animal.prototype.say = function() {
    console.log( this.name + " says: " + this.sound );
}

Cat = function () {
    this.name = "Cat";
    this.sound = "meow";
}

Dog = function() {
    this.name = "Dog";
    this.sound  = "woof";
}

Cat.prototype = Object.create(Animal.prototype);
Dog.prototype = Object.create(Animal.prototype);

new Cat().say();    //Cat says: meow
new Dog().say();    //Dog says: woof 
new Animal().say(); //Uncaught abstract class!

0 votes

Le constructeur d'une sous-classe peut-il invoquer le constructeur de la super-classe ? (comme appeler super dans un langage... si c'est le cas, alors il lèvera inconditionnellement une exception)

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