How do I create an abstract base class in JavaScript?

后端 未结 17 2042
無奈伤痛
無奈伤痛 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:43

    One simple way to create an abstract class is this:

    /**
     @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!");
    }
    

    The Animal "class" and the say method are abstract.

    Creating an instance would throw an error:

    new Animal(); // throws
    

    This is how you "inherit" from it:

    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 looks just like it.

    And this is how your scenario plays out:

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

    Fiddle here (look at the console output).

    0 讨论(0)
  • 2020-12-02 04:43

    Javascript can have inheritance, check out the URL below:

    http://www.webreference.com/js/column79/

    Andrew

    0 讨论(0)
  • 2020-12-02 04:44

    JavaScript Classes and Inheritance (ES6)

    According to ES6, you can use JavaScript classes and inheritance to accomplish what you need.

    JavaScript classes, introduced in ECMAScript 2015, are primarily syntactical sugar over JavaScript's existing prototype-based inheritance.

    Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes

    First of all, we define our abstract class. This class can't be instantiated, but can be extended. We can also define functions that must be implemented in all classes that extends this one.

    /**
     * Abstract Class Animal.
     *
     * @class Animal
     */
    class Animal {
    
      constructor() {
        if (this.constructor == Animal) {
          throw new Error("Abstract classes can't be instantiated.");
        }
      }
    
      say() {
        throw new Error("Method 'say()' must be implemented.");
      }
    
      eat() {
        console.log("eating");
      }
    }
    

    After that, we can create our concrete Classes. These classes will inherit all functions and behaviour from abstract class.

    /**
     * Dog.
     *
     * @class Dog
     * @extends {Animal}
     */
    class Dog extends Animal {
      say() {
        console.log("bark");
      }
    }
    
    /**
     * Cat.
     *
     * @class Cat
     * @extends {Animal}
     */
    class Cat extends Animal {
      say() {
        console.log("meow");
      }
    }
    
    /**
     * Horse.
     *
     * @class Horse
     * @extends {Animal}
     */
    class Horse extends Animal {}
    

    And the results...

    // RESULTS
    
    new Dog().eat(); // eating
    new Cat().eat(); // eating
    new Horse().eat(); // eating
    
    new Dog().say(); // bark
    new Cat().say(); // meow
    new Horse().say(); // Error: Method say() must be implemented.
    
    new Animal(); // Error: Abstract classes can't be instantiated.
    
    0 讨论(0)
  • 2020-12-02 04:44

    Question is quite old, but I created some possible solution how to create abstract "class" and block creation of object that type.

    //our Abstract class
    var Animal=function(){
      
        this.name="Animal";
        this.fullname=this.name;
        
        //check if we have abstract paramater in prototype
        if (Object.getPrototypeOf(this).hasOwnProperty("abstract")){
        
        throw new Error("Can't instantiate abstract class!");
        
        
        }
        
    
    };
    
    //very important - Animal prototype has property abstract
    Animal.prototype.abstract=true;
    
    Animal.prototype.hello=function(){
    
       console.log("Hello from "+this.name);
    };
    
    Animal.prototype.fullHello=function(){
    
       console.log("Hello from "+this.fullname);
    };
    
    //first inheritans
    var Cat=function(){
    
    	  Animal.call(this);//run constructor of animal
        
        this.name="Cat";
        
        this.fullname=this.fullname+" - "+this.name;
    
    };
    
    Cat.prototype=Object.create(Animal.prototype);
    
    //second inheritans
    var Tiger=function(){
    
        Cat.call(this);//run constructor of animal
        
        this.name="Tiger";
        
        this.fullname=this.fullname+" - "+this.name;
        
    };
    
    Tiger.prototype=Object.create(Cat.prototype);
    
    //cat can be used
    console.log("WE CREATE CAT:");
    var cat=new Cat();
    cat.hello();
    cat.fullHello();
    
    //tiger can be used
    
    console.log("WE CREATE TIGER:");
    var tiger=new Tiger();
    tiger.hello();
    tiger.fullHello();
    
    
    console.log("WE CREATE ANIMAL ( IT IS ABSTRACT ):");
    //animal is abstract, cannot be used - see error in console
    var animal=new Animal();
    animal=animal.fullHello();

    As You can see last object give us error, it is because Animal in prototype has property abstract. To be sure it is Animal not something which has Animal.prototype in prototype chain I do:

    Object.getPrototypeOf(this).hasOwnProperty("abstract")
    

    So I check that my closest prototype object has abstract property, only object created directly from Animal prototype will have this condition on true. Function hasOwnProperty checks only properties of current object not his prototypes, so this gives us 100% sure that property is declared here not in prototype chain.

    Every object descended from Object inherits the hasOwnProperty method. This method can be used to determine whether an object has the specified property as a direct property of that object; unlike the in operator, this method does not check down the object's prototype chain. More about it:

    In my proposition we not have to change constructor every time after Object.create like it is in current best answer by @Jordão.

    Solution also enables to create many abstract classes in hierarchy, we need only to create abstract property in prototype.

    0 讨论(0)
  • 2020-12-02 04:46
    function Animal(type) {
        if (type == "cat") {
            this.__proto__ = Cat.prototype;
        } else if (type == "dog") {
            this.__proto__ = Dog.prototype;
        } else if (type == "fish") {
            this.__proto__ = Fish.prototype;
        }
    }
    Animal.prototype.say = function() {
        alert("This animal can't speak!");
    }
    
    function Cat() {
        // init cat
    }
    Cat.prototype = new Animal();
    Cat.prototype.say = function() {
        alert("Meow!");
    }
    
    function Dog() {
        // init dog
    }
    Dog.prototype = new Animal();
    Dog.prototype.say = function() {
        alert("Bark!");
    }
    
    function Fish() {
        // init fish
    }
    Fish.prototype = new Animal();
    
    var newAnimal = new Animal("dog");
    newAnimal.say();
    

    This isn't guaranteed to work as __proto__ isn't a standard variable, but it works at least in Firefox and Safari.

    If you don't understand how it works, read about the prototype chain.

    0 讨论(0)
  • 2020-12-02 04:46
    /****************************************/
    /* version 1                            */
    /****************************************/
    
    var Animal = function(params) {
        this.say = function()
        {
            console.log(params);
        }
    };
    var Cat = function() {
        Animal.call(this, "moes");
    };
    
    var Dog = function() {
        Animal.call(this, "vewa");
    };
    
    
    var cat = new Cat();
    var dog = new Dog();
    
    cat.say();
    dog.say();
    
    
    /****************************************/
    /* version 2                            */
    /****************************************/
    
    var Cat = function(params) {
        this.say = function()
        {
            console.log(params);
        }
    };
    
    var Dog = function(params) {
        this.say = function()
        {
            console.log(params);
        }
    };
    
    var Animal = function(type) {
        var obj;
    
        var factory = function()
        {
            switch(type)
            {
                case "cat":
                    obj = new Cat("bark");
                    break;
                case "dog":
                    obj = new Dog("meow");
                    break;
            }
        }
    
        var init = function()
        {
            factory();
            return obj;
        }
    
        return init();
    };
    
    
    var cat = new Animal('cat');
    var dog = new Animal('dog');
    
    cat.say();
    dog.say();
    
    0 讨论(0)
提交回复
热议问题