6 Ways of Inheritance in JavaScript
This article is going to talk about the Inheritance
in JavaScript.
Inheritance is a concept belonging to Object-Oriented Programming (OOP), using which we can have a elegent way to reuse codes and manage entity relationships.
Before we start, let me ask you a couple of questions:
- How many ways for inheritance are there in JavaScript?
- What’s under the hood of ES6 keyword
extends
?
If you seem to feel hesitate about them, then don’t hesitate to walk through with me.
6 Ways for interitance (ES5)
Method 1: Prototype Chain Interitance
Prototype chain inheritance is one of the most common way in JavaScript. It includes constructor
, prototype
and instance
. The relationships among them are:
- Every
constructor function
has aprototype object
- Every
prototype object
contains a pointer to itsconstructor function
- Every instance contains a pointer to its
prototype object
Let’s watch a demo for this:
1 | function Parent1() { |
It has a severe problem:
1 | var s1 = new Child1(); |
Why is this happening? Because the two instances use the same prototype. It’s one of the biggest drawbacks for Prototype Chain Inheritance
.
So let’s move on to the next method that helps with this issue.
Method 2: Constructor Inheritance (by using call)
Watch this demo:
1 | function Parent1(){ |
Now we solve the problem of the method one, i.e. we get the properties from the parent. However, we lose the prototype functions of the parent too.
So this method only allows us to inherit the instance properties and functions from parents instead of prototypal ones.
What if we combine the above two worlds?
Method 3: Combination Inheritance
We combine the prototype inheritance as well as the constructor inheritance, and here we go:
1 | function Parent3 () { |
Now we’re getting things done, but not perfectly. See we called Parent 3 twice? The first time is to change Child3’s protoype while the other time is within the constructor function Child3
. This may have performance concerns, which we definitly want to avoid.
We will leave this question to the Six method. Before that, we are going to introduce some inheritance ways using object
rather than constructor function
.
Method 4: Prototypal Inheritance
Prototypal inheritance
is a way of creating an object that inherits the properties and methods of another object, using the prototype object.
Watch out ladies and gentlemen, we are inheriting straightly from an object! How does the magic work?
We got to mention an ES5 method called Object.create
, which takes up two params: the first one is for the model object, the second one is for the object that defines additional properties for our new born object.
Take a look at the example of how we implement inheritance from an object:
1 | let parent4 = { |
We see that Object.create
enables our new objects to inherit the properties from parent4
. But we do see it has the same reference problem here, a.k.a shallow cloning.
Method 5: Parasitic Inheritance
Parasitic Inheritance
does not solve the issues as Prototypal Inheritance
has, but it adds some own functions beyond the shallow cloning from parents.
1 | let parent5 = { |
Adding more functions rather than just copying from parent objects, that’s parasitic inheritance.
Method 6: Parasitic Combination Inheritance
Concluding all the methods above, we get a relatively better solution.
1 | function clone (parent, child) { |
Regarding the result, we are getting the properties and functions properly for the child from the parent.
In a nutshell, we finally find out a good way for inheritance in JavaScript, which considers:
- Inheritance of parent’s instance properties without the same reference issue.
- Inheritance of parent’s prototype functions
- Only once call for parent constructor
And after ES6 came out, there is an offical way to do it!
Method 7: Extends (ES6)
1 | class Person { |
Things just go smooth because of the occurance of class
and extends
. But there are compatiblity issues for old versions of browsers, if we want the above ES6 syntax work on those browsers, we need a transformer called Babel
to compile ES6 to ES5.
Now we’re gonna uncover the real face under ES6 syntax class
and extends
, which inheritance method does it use?
1 | function _possibleConstructorReturn (self, call) { |
Wow, we see parasitic combination inheritance
under the hood, that means it is a good way to do inheritance in JavaScript!
Summary
We’ve seen 6 ways to do inheritance and their pros and cons, and we’ve also uncover the mystery of ES6 extends. Take the below mind graph as reviewing:
Divied by using object.create
or not, we finally pick Parasitic Combination Inheritance as our preference.
What a journey, see you next time!