JavaScript Inheritance
JavaScript is a class-free object-oriented language. it uses prototypical inheritance instead of classical inheritance. Prototypical inheritance is more powerful and expressive than Classical inheritance. If you are not aware of JavaScript prototype please refer our previous blogs related to closure, prototype and prototype chaining. It will give you a clear idea about the JavaScript prototype.
Then why do we care about the inheritance ? There are primarily two reasons. The first type is convenience. We want the language system automatically cast references of similar classes. Little type safety where system requires the routine explicitly cast to object references. This is critical requirement in strongly typed languages but it is irrelevant in loosely-typed languages like JavaScript where object reference never need casting.
The second reason is code reuse. It is very common to have a quantity of objects implementing same code. So code reuse is a major aspect in the area of maintenance and continuous development. So Share the common code in parent and the child classes can reuse the common logic. Surely in the next blogs you can get some core implementations how to implement inheritance in JavaScript, till now you can refer this blog.
This blog is the extension of Prototype Chaining, which is my previous blog. You can refer the blog for more details.
Inheriting the Prototype
As we know we have placed all the reusable components like methods, properties in the prototype. so there is no need of create new object line new Shape() and add it to the child prototype. This means, it is better to inherit the object Shape.prototype instead of the object created from new Shape(). The new Shape() will give you all the Shape related properties which are not meant to be reused. Lets Create a sample of it.
//Rewrite of Shape
function Shape(){};
Shape.prototype.name = "Shape";
Shape.prototype.toString = function(){
return this.name;
}
//Rewrite of TwoDShape
function TwoDShape(){};
TwoDShape.prototype = Shape.prototype;
TwoDShape.prototype.constructor = TwoDShape;
TwoDShape.prototype.name = "2D Shape";
//Rewrite the ThreeDShape
function ThreeDShape(side, height){
this.side = side;
this.height = height;
}
ThreeDShape.prototype = TwoDShape.prototype;
ThreeDShape.prototype.constructor = ThreeDShape;
ThreeDShape.prototype.name = "Triangle";
ThreeDShape.prototype.getArea = function(){
return 0.5 * this.side * this.height;
}
Code language: JavaScript (javascript)
Simply coping prototype is efficient and has a side effect. As all the children and parent points to same object, any modification to child will be reflected in parent and also with the siblings. now check the following observations.
ThreeDShape.prototype.name = "Triangle";
var spape = new Shape();
shape.name; // it will give you "Triangle"
Code language: JavaScript (javascript)
When we change the name in the prototype of ThreeDShape, It will automatically change the name in Shape.prototype due to prototype chaining. so the name property of shape object will give us “Triangle” instead of “Shape”. So how can we fix it.
Here all the prototype pointing to the same and the parent get’s the children prototype. To fix this we have to add a intermediatary to break the prototype chain, by using temporary constructor new F(). let’s check the code.
Create temporary constructor : new F()
//Rewrite of Shape
function Shape(){};
Shape.prototype.name = "Shape";
Shape.prototype.toString = function(){
return this.name;
}
//Rewrite of TwoDShape
function TwoDShape(){};
// we have created a intermediatary funtion
var F = function() {};
// Updating intermediatary prototype
F.prototype = Shape.prototype;
// Assigning TwoDShape prototype to the instance of intermediatary function
TwoDShape.prototype = new F();
TwoDShape.prototype.constructor = TwoDShape;
TwoDShape.prototype.name = "2D Shape";
//Rewrite the ThreeDShape
function ThreeDShape(side, height){
this.side = side;
this.height = height;
}
var F = function() {};
F.prototype = TwoDShape.prototype;
ThreeDShape.prototype = new F();
ThreeDShape.prototype.constructor = ThreeDShape;
ThreeDShape.prototype.name = "Triangle";
ThreeDShape.prototype.getArea = function(){
return 0.5 * this.side * this.height;
}
Code language: JavaScript (javascript)
Here we break the prototype chain through temporary constructor : new F() and it will add a secret link as “proto“, which will points to the parents prototype.
How to call superclass properties from child object ?
In classical Object oriented model usually we have a special syntax to access superclass properties. The main reason of it we will add out common logic in the parent. Where child will do the same as the parent with some additional functionality. i.e. child will call the parent method with the same name as the child and adds the extra statements in its own method.
In JavaScript there is no such keywords to call parents but we can add some functionality like “superclass” to call the superclass methods. Following are the code snippets.
//Rewrite of Shape
function Shape(){};
Shape.prototype.name = "Shape";
Shape.prototype.toString = function(){
if(this.constructor.superclass){
return this.name + ", " + this.constructor.superclass.toString();
}
return this.name;
}
//Rewrite of TwoDShape
function TwoDShape(){};
// we have created a intermediatary funtion
var F = function() {};
// Updating intermediatary prototype
F.prototype = Shape.prototype;
// Assigning TwoDShape prototype to the instance of intermediatary function
TwoDShape.prototype = new F();
TwoDShape.prototype.constructor = TwoDShape;
//We are keeping the reference of parents prototype in the child
TwoDShape.superclass = Shape.prototype;
TwoDShape.prototype.name = "2D Shape";
//Rewrite the ThreeDShape
function ThreeDShape(side, height){
this.side = side;
this.height = height;
}
var F = function() {};
F.prototype = TwoDShape.prototype;
ThreeDShape.prototype = new F();
ThreeDShape.prototype.constructor = ThreeDShape;
//We are keeping the reference of parents prototype in the child
ThreeDShape.superclass = TwoDShape.prototype;
ThreeDShape.prototype.name = "Triangle";
ThreeDShape.prototype.getArea = function(){
return 0.5 * this.side * this.height;
}
Code language: JavaScript (javascript)
var triangle = new ThreeDShape(10, 20);
triangle.toString(); // will give you "Triangle, 2D Shape, Shape"
Code language: JavaScript (javascript)
Now see the toString() method defined in Shape class. If we call the toString() method from the triangle object, then it will call the superclass toString() and like this. This call chain will be executed until we reached the ultimate parent as per the logic implemented.
Let Isolate inheritance implementation to a common method.
For inheritance as we saw we have some common codes like Prototype assignment, updating the constructor, and the use of temporary constructor. All the implementations can be done by a generic method and it will hold the implementation of the inheritance. let’s implement the method.
function extent(Child, Parent){
var F = function() {};
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
//We are keeping the reference of parents prototype in the child
Child.superclass = Parent.prototype;
}
Code language: JavaScript (javascript)
Let’s rewrite the complete code and see the implementation for the extend(). I think you got the basic knowledge about inheritance.
//Rewrite of Shape
function Shape(){};
Shape.prototype.name = "Shape";
Shape.prototype.toString = function(){
if(this.constructor.superclass){
return this.name + ", " + this.constructor.superclass.toString();
}
return this.name;
}
//Rewrite of TwoDShape
function TwoDShape(){};
extend(TwoDShape, Shape);
TwoDShape.prototype.name = "2D Shape";
//Rewrite the ThreeDShape
function ThreeDShape(side, height){
this.side = side;
this.height = height;
}
extend(ThreeDShape, TwoDShape);
ThreeDShape.prototype.name = "Triangle";
ThreeDShape.prototype.getArea = function(){
return 0.5 * this.side * this.height;
}
Code language: JavaScript (javascript)
How to implement multiple inheritance ?
By the previous approach we can not target the multiple inheritance as when we extend one class from other it will completely overwrite the prototype so the recent parent will take the advantage and will involve in inheritance. To achieve this we have to slightly change our implementation. what is this ?
The multiple inheritance can be achieved through the mixin. so what is mixin ? In mixin child will copy the prototype properties of the parent without overwriting it’s prototype. Means it will copy all the properties from the parent prototype to child prototype. Let’s implement the mixin;
function mixin(){
var args = Array.prototype.slice.call(arguments), Child, Parent;
Child = args[0];
args = args.slice(1);
for(var i = 0, ln = args.length; i < ln; i++){
Parent = args[i];
for(var key in Parent.prototype){
Child.prototype[key] = Parent.prototype[key];
}
}
}
Code language: JavaScript (javascript)
let’s implement some samples of mixin.
function MathUtils(){};
MathUtils.prototype.sumOfSides = function(){
return this.height * 3; //Just asume that
}
MathUtils.prototype.getCentroid = function(){
var centroid;
.... //Clculation for centroid
return centroid; //Just asume that
}
extend(ThreeDShape, TwoDShape); // extend from parent TwoDShape;
mixin(ThreeDShape, MathUtils);
var triangle = new ThreeDShape(10, 20);
triangle.getArea(); // will return the Area
triangle.sumOfSides(); // Is defined in MathUtils;
triangle.getCentroid(); // Is defined in MathUtils;
Code language: JavaScript (javascript)
The above one is a sample demonstration of the implemention of mixin. Where ThreeDShape mixins the MathUtils class and the methods defined in the MathUtil will be available in the ThreeDShape as in mixin we are copying the properties.
Very very important : While copying properties javascript will copy the properties for primitive types but for the objects (Functions, Arrays, Objects) it will copy the reference.
How to call superclass constructor ?
When a class in being instantiated, it first call the constructor and the invocation of constructor will chain upto the base class. But what we have implemented till now will not invoke the superclass constructor as we have a mechanism to invoke superclass method. The invocation of constructor is little bit different. Let’s write the code to invoke the superclass constructor.
//Rewrite of Shape
function Shape(){};
Shape.prototype.name = "Shape";
Shape.prototype.toString = function(){
if(this.constructor.superclass){
return this.name + ", " + this.constructor.superclass.toString();
}
return this.name;
}
//Rewrite of TwoDShape
function TwoDShape(){
this.constructor.superclass.constructor.apply(this, arguments);
};
extend(TwoDShape, Shape);
TwoDShape.prototype.name = "2D Shape";
//Rewrite the ThreeDShape
function ThreeDShape(side, height){
this.side = side;
this.height = height;
this.constructor.superclass.constructor.apply(this, arguments);
}
extend(ThreeDShape, TwoDShape);
ThreeDShape.prototype.name = "Triangle";
ThreeDShape.prototype.getArea = function(){
return 0.5 * this.side * this.height;
}
Code language: JavaScript (javascript)
var triangle = new ThreeDShape(10, 20);
Code language: JavaScript (javascript)
Now see when we instantiate the ThreeDShape(), it will call the superclass constructor with the arguments through the apply() method. it will invoke the constructor with the newly created instance scope. If you have any doubts regarding the inheritance in JavaScript, please provide your comments. Surely I try my best to resolve your doubt.