Inheritance in JavaScript: A brief overview
Why is inheritance useful, example & related concepts
Inheritance is a phenomenon where some object (the child) extends the properties of some other object (the parent), just like we as humans inherit properties from our parents. Inheritance is one of the main pillars of object oriented programming. In this article we'll explore how inheritance and some of its key features work in JavaScript.
Why is Inheritance useful?
Let's say two objects share a common property, and both objects are of similar type:
function Bus(wheels) {
this.wheels = wheels;
}
Bus.prototype = {
constructor: Bus,
printWheelCount() {
console.log("No. of wheels: " + this.wheels);
}
}
function Bike(wheels) {
this.wheels = wheels;
}
Bike.prototype = {
constructor: Bike,
printWheelCount() {
console.log("No. of wheels: " + this.wheels);
}
}
As we can see, both the constructors Bus & Bike share a common printWheelCount() property, so we are writing the same code twice by including it in both prototypes separately. There's a way to make this code reusable, and that is where inheritance comes in. Since the classes Bus & Bike are of similar types, we can make a super class Vehicle, and add the common property to the super class. Then, we can inherit the properties of Vehicle inside Bus & Bike. This is how inheritance helps us in following the DRY principle in programming. Now that we understand why inheritance is useful, let's see an example of it.
Example of an Inheritance chain
Let's continue from the previous example. We'll create a super class Vehicle and add the printWheelCount() property to it's prototype.
function Vehicle() {}
Vehicle.prototype = {
constructor: Vehicle,
printWheelCount() {
console.log("No. of wheels: " + this.wheels);
}
}
Then, we can remove the printWheelCount() property from the Bus & Bike prototypes. Now comes the part of inheriting the Vehicle class from the Bus & Bike classes. We can do so by forming a prototype chain. We'll use the Object.create() syntax for this. For inheritance, we need to make the parent class' prototype the prototype of the child class. We can achieve the same like this:
child.prototype = Object.create(parent.prototype);
This will set the prototype of the parent as the prototype of the child's prototype. Thus, a prototype chain will be formed between the child and the parent. So let's do this for the Bus & Bike classes.
Bike.prototype = Object.create(Vehicle.prototype);
Bus.prototype = Object.create(Vehicle.prototype);
Now, the inheritance chain is formed, let's check that it's working properly now.
const ninja = new Bike(2);
ninja.printWheelCount(); // No of wheels: 2
But there's one small problem we need to fix. Let's check the constructor of the ninja object:
console.log(ninja.constructor); //ฦ Vehicle() {};
So we see that the constructor of the ninja object is set to Vehicle, and not Bike. Let's understand why this happened and fix this.
Resetting the child constructor
Because we directly set the child's prototype (child.prototype = Object.create(parent.prototype)), the constructor property of the child was also set to the parent's constructor. So, we need to set it back to its own constructor as an additional step after inheritance is formed.
Bike.prototype.constructor = Bike;
Bus.prototype.constructor = Bus;
That's it! We have successfully implemented inheritance in JavaScript. Now let's see some more features related to inheritance we could make use of.
Adding more methods after inheritance
Inheritance gives us the ability to extend parent object's properties inside a child object. But we might also want to add some properties unique to the child object, after inheritance. We can easily do this but adding additional methods to the child object prototype.
Bike.prototype.refuel = function() {
console.log("Refuelling bike");
}
Overriding inherited methods
If we want to override any inherited methods inside a child object, we can also do that in JS. Let's override the printWheelCount() method inherited from Vehicle inside the Bike object:
Bike.prototype.printWheelCount = function() {
console.log("A bike has 2 wheels only");
}
Additional: Mixins
Inheritance is a great way for sharing properties among related objects, but not so much for unrelated objects. For example, a Bird & an AeroPlane both fly, but they are not objects of the same type. We can use mixins to solve this problem. A mixin is a function that takes an object as a parameter and adds some property to that object. For example:
const flyMixin = function(obj) {
obj.fly = function() {
console.log("I'm flying!");
}
}
Let's say we have two bird & plane objects like this:
let bird = {
name: "Eagle"
};
let plane = {
company: "Boeing"
};
We can use the flyMixin to attach a property fly() to both these objects.
flyMixin(bird);
flyMixin(plane);
console.log(bird.fly()); //I'm flying!
Final words
That's it! We have covered most topics related to inheritance in JS, along with some additional concepts like mixins! Hope you enjoyed learning about Inheritance in JS, and how it can be useful. Let's get connected on LinkedIn & Twitter so we can keep the mutual learning going! See you soon! ๐