How do I create an abstract base class in JavaScript?

后端 未结 17 2043
無奈伤痛
無奈伤痛 2020-12-02 04:06

Is it possible to simulate abstract base class in JavaScript? What is the most elegant way to do it?

Say, I want to do something like: -

var cat = ne         


        
相关标签:
17条回答
  • 2020-12-02 04:48

    Is it possible to simulate abstract base class in JavaScript?

    Certainly. There are about a thousand ways to implement class/instance systems in JavaScript. Here is one:

    // 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');

    That's not really an abstract base class of course. Do you mean something like:

    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 讨论(0)
  • 2020-12-02 04:52
    //Your Abstract class Animal
    function Animal(type) {
        this.say = type.say;
    }
    
    function catClass() {
        this.say = function () {
            console.log("I am a cat!")
        }
    }
    function dogClass() {
        this.say = function () {
            console.log("I am a dog!")
        }
    }
    var cat = new Animal(new catClass());
    var dog = new Animal(new dogClass());
    
    cat.say(); //I am a cat!
    dog.say(); //I am a dog!
    
    0 讨论(0)
  • 2020-12-02 04:52

    I think All Those answers specially first two (by some and jordão) answer the question clearly with conventional prototype base JS concept.
    Now as you want the animal class constructor to behave according to the passed parameter to the construction, I think this is very much similar to basic behavior of Creational Patterns for example Factory Pattern.

    Here i made a little approach to make it work that way.

    var Animal = function(type) {
        this.type=type;
        if(type=='dog')
        {
            return new Dog();
        }
        else if(type=="cat")
        {
            return new Cat();
        }
    };
    
    
    
    Animal.prototype.whoAreYou=function()
    {
        console.log("I am a "+this.type);
    }
    
    Animal.prototype.say = function(){
        console.log("Not implemented");
    };
    
    
    
    
    var Cat =function () {
        Animal.call(this);
        this.type="cat";
    };
    
    Cat.prototype=Object.create(Animal.prototype);
    Cat.prototype.constructor = Cat;
    
    Cat.prototype.say=function()
    {
        console.log("meow");
    }
    
    
    
    var Dog =function () {
        Animal.call(this);
        this.type="dog";
    };
    
    Dog.prototype=Object.create(Animal.prototype);
    Dog.prototype.constructor = Dog;
    
    Dog.prototype.say=function()
    {
        console.log("bark");
    }
    
    
    var animal=new Animal();
    
    
    var dog = new Animal('dog');
    var cat=new Animal('cat');
    
    animal.whoAreYou(); //I am a undefined
    animal.say(); //Not implemented
    
    
    dog.whoAreYou(); //I am a dog
    dog.say(); //bark
    
    cat.whoAreYou(); //I am a cat
    cat.say(); //meow
    
    0 讨论(0)
  • 2020-12-02 04:56

    Another thing you might want to enforce is making sure your abstract class is not instantiated. You can do that by defining a function that acts as FLAG ones set as the Abstract class constructor. This will then try to construct the FLAG which will call its constructor containing exception to be thrown. Example below:

    (function(){
    
        var FLAG_ABSTRACT = function(__class){
    
            throw "Error: Trying to instantiate an abstract class:"+__class
        }
    
        var Class = function (){
    
            Class.prototype.constructor = new FLAG_ABSTRACT("Class");       
        }
    
        //will throw exception
        var  foo = new Class();
    
    })()
    
    0 讨论(0)
  • 2020-12-02 04:57

    Do you mean something like this:

    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 讨论(0)
  • 2020-12-02 05:00
    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 讨论(0)
提交回复
热议问题