Implement abstract classes in JavaScript

Understanding the implementation of abstract classes is conducive to accumulating the ability to create your own JavaScript framework/library. Prior t

wang xiao bo 's photo
wang xiao bo

Published on Oct 3, 2021

4 min read

Subscribe to my newsletter and never miss my upcoming articles

Abstract classes and virtual methods A virtual method is a concept in class members. It is a method that has only been declared but not implemented.

-A class with virtual methods is called an abstract class. -These virtual methods are implemented in derived classes. -An abstract class cannot be instantiated, because the virtual method in it is not a complete function and cannot be called. -Therefore, abstract classes are generally only used as base classes after being derived.

Implement abstract class

In traditional object-oriented languages, virtual methods in abstract classes must be declared first, but they can be called in other methods. In JavaScript, virtual methods can be regarded as methods that are not defined in the class, but have been used through the this pointer. Unlike traditional object-oriented methods, virtual methods are used directly without declaration. These methods will be implemented in derived classes, for example:

//Define the extend method
Object.extend = function(destination, source) {
for (property in source) {
destination[property] = source[property];
}
return destination;
}
Object.prototype.extend = function(object) {
return Object.extend.apply(this, [this, object]);
}
//Define an abstract base class base, no constructor
function base(){}
base.prototype={
initialize:function(){
this.oninit(); //Called a virtual method
}
}
//Define class1
function class1(){
//Constructor
}
//Let class1 inherit from base and implement the oninit method in it
class1.prototype=(new base()).extend({
oninit:function(){ //Implement the oninit virtual method in the abstract base class
//Implementation of oninit function
}
});

In this way, when the inherited initialize method is called in an instance of class1, the oninit() method in the derived class will be automatically executed. From here, we can also see the characteristics of the execution of interpreted languages. They will only check whether the method exists when they run to a certain method call, instead of checking the existence of the method at the compilation stage like a compiled language. JavaScript avoids this problem. Of course, if you want to add a definition of a virtual method to the base class, it is also possible, as long as this method is overridden in the derived class. E.g

//Define an abstract base class base, no constructor
function base(){}
base.prototype={
initialize:function(){
this.oninit(); //Called a virtual method
},
oninit:function(){} //Virtual method is an empty method, implemented by derived classes
}

Example Here Class is a global object, with a method create, used to return a function (class), so as to declare a class, you can use the following syntax:

var class1=Class.create();

This distinguishes it from the way the function is defined, so that the JavaScript language can have the characteristics of an object-oriented language. Now look at the returned function (class):

function(){
      this.initialize.apply(this, arguments);
}

This function is also the constructor of a class, and it will be executed when the class is new. It calls an initialize method, which, judging from the name, is the constructor of the class. From the perspective of the class, it is a virtual method and is undefined. But the implementation of this virtual method is not implemented in the derived class, but defined in the prototype after creating a class. For example, the prototype can be written like this:

var class1=Class.create();
class1.prototype={
      initialize:function(userName){
                      alert(“hello,”+userName);
      }
}

In this way, every time an instance of the class is created, the initialize method will be executed, thus realizing the function of defining the class constructor and class members together. Among them, in order to be able to pass parameters to the constructor, such a statement is used:

function(){
      this.initialize.apply(this, arguments);
}

In fact, the arguments here are the parameters passed in in function(), that is, the args passed in in new class1 (args). Now you have to pass args to initialize. The apply method of the function is used cleverly. Note that it cannot be written as :

this.initialize(arguments);

This is to pass the arguments array as a parameter to the initialize method, and the apply method can pass the elements of the arguments array object as a set of parameters. This is a very clever implementation. Although this example is not an abstract class concept in prototype-1.3.1, but a design pattern of classes. But in fact, the class returned by Class.create() can be regarded as the common base class of all classes. It calls a virtual method initialize in the constructor. All classes inheriting from it must implement this method to complete the constructor. Function. The essence of their realization is the operation of the prototype.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <title></title>
    <script type="text/javascript" src="js/prototype-1.6.0.3.js"></script>
    <script type="text/javascript" src="js/Person.js"></script>
    <script type="text/javascript" src="js/Employee.js"></script>
    <script type="text/javascript">
        //Create a class
       function getEmployeeInfo(){
           var employee = new Employee("sunliyuan","Miscofo");
           var info = employee.showInfo();
           alert(info);
       }
    </script>
</head>
<body>
<button onclick="getEmployeeInfo()">GetEmployeeInfo</button>
</body>
</html>

Parent js:

var Person = Class.create();
Person.prototype={
//Must give initial value
initialize: function(name) {
this.personName=name;
},
showInfo:function(){
alert(this.personName);
}
}

Subclass of js:

var Employee = Class.create();

Employee.prototype = Object.extend(new Person(), {
//Define an abstract class
    initialize: function(name,corp) {
        this.personName=name;
        this.corpName=corp;
    },
    // corpName:"Micosoft",
    showInfo:function(){
        return this.personName+","+this.corpName;
    }
});
 
Share this