[javascript] How do I create an abstract base class in JavaScript?

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 = new Animal('cat');
var dog = new Animal('dog');

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

It should output: 'bark', 'meow'

This question is related to javascript oop abstract

The answer is


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.


If you want to make sure that your base classes and their members are strictly abstract here is a base class that does this for you:

class AbstractBase{
    constructor(){}
    checkConstructor(c){
        if(this.constructor!=c) return;
        throw new Error(`Abstract class ${this.constructor.name} cannot be instantiated`);
    }
    throwAbstract(){
        throw new Error(`${this.constructor.name} must implement abstract member`);}    
}

class FooBase extends AbstractBase{
    constructor(){
        super();
        this.checkConstructor(FooBase)}
    doStuff(){this.throwAbstract();}
    doOtherStuff(){this.throwAbstract();}
}

class FooBar extends FooBase{
    constructor(){
        super();}
    doOtherStuff(){/*some code here*/;}
}

var fooBase = new FooBase(); //<- Error: Abstract class FooBase cannot be instantiated
var fooBar = new FooBar(); //<- OK
fooBar.doStuff(); //<- Error: FooBar must implement abstract member
fooBar.doOtherStuff(); //<- OK

Strict mode makes it impossible to log the caller in the throwAbstract method but the error should occur in a debug environment that would show the stack trace.


You can create abstract classes by using object prototypes, a simple example can be as follows :

var SampleInterface = {
   addItem : function(item){}  
}

You can change above method or not, it is up to you when you implement it. For a detailed observation, you may want to visit here.


/****************************************/
/* 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();

//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!

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

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

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.


Javascript can have inheritance, check out the URL below:

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

Andrew


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.

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

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!

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();

})()

You might want to check out Dean Edwards' Base Class: http://dean.edwards.name/weblog/2006/03/base/

Alternatively, there is this example / article by Douglas Crockford on classical inheritance in JavaScript: http://www.crockford.com/javascript/inheritance.html


We can use Factory design pattern in this case. Javascript use prototype to inherit the parent's members.

Define the parent class constructor.

var Animal = function() {
  this.type = 'animal';
  return this;
}
Animal.prototype.tired = function() {
  console.log('sleeping: zzzZZZ ~');
}

And then create children class.

// These are the child classes
Animal.cat = function() {
  this.type = 'cat';
  this.says = function() {
    console.log('says: meow');
  }
}

Then define the children class constructor.

// Define the child class constructor -- Factory Design Pattern.
Animal.born = function(type) {
  // Inherit all members and methods from parent class,
  // and also keep its own members.
  Animal[type].prototype = new Animal();
  // Square bracket notation can deal with variable object.
  creature = new Animal[type]();
  return creature;
}

Test it.

var timmy = Animal.born('cat');
console.log(timmy.type) // cat
timmy.says(); // meow
timmy.tired(); // zzzZZZ~

Here's the Codepen link for the full example coding.


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

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).


Reference: https://developer.mozilla.org/pl/docs/Web/JavaScript/Reference/Classes

class Animal {
  
  constructor(sound) {
    this.sound = sound;
      }

  say() {
    return `This animal does ${this.sound}`;}

};

const dog = new Animal('bark');
console.log(dog.say());

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! 

Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to oop

How to implement a simple scenario the OO way When to use 'raise NotImplementedError'? PHP: cannot declare class because the name is already in use Python class input argument Call an overridden method from super class in typescript Typescript: How to extend two classes? What's the difference between abstraction and encapsulation? An object reference is required to access a non-static member Java Multiple Inheritance Why not inherit from List<T>?

Examples related to abstract

Can we instantiate an abstract class? Is it possible to make abstract classes in Python? Java abstract interface Abstract methods in Java Defining an abstract class without any abstract methods Can we instantiate an abstract class directly? Abstract methods in Python Abstract variables in Java? How do I create an abstract base class in JavaScript? What is the difference between an abstract function and a virtual function?