Object-oriented programming in JavaScript #3. Polymorphism.

Viktor Kukurba
4 min readApr 6, 2019

--

In this story we are going to investigate polymorphism in JavaScript ES7 specification.

But first let’s go back to the types of inheritance, because it has a really important relationship with polymorphism.

On the left side of the slide there is a type that we’ve investigated in the previous article and it is called “IS A” inheritance. It means that instance of any child class is still a type of parent class, or from JS syntaxes perspective it’s better to say an instance of parent class.

And on the right side of the slide you may see another alternative approach that is called “HAS A” inheritance or composition. In this case inheriting class (ClassB) is not an instance of a “super” (ClassA) but has a property with an instance of an inherited class.

Instances of both types of inheritance contain the same functionality but a different interface to access it, both approaches can be preferred in specific situations.

Composition (“HAS A”) gives a different way of flexibility in extending class, which means that it is better to compose what an object can do than extend what it is. Often it can be used for Inversion of Control and Dependency Injection. Typed languages with ability to use interfaces still provide an efficient way to simulate “IS A” principle in composition. At this point JS does not have support of interfaces which can help to do it in a much more efficient and clearer way, but still you can wrap execution of “HAS A” property into same interface.

“IS A” inheritance provides abilities to implement polymorphism principle. Let’s try to describe what it means in few definitions.

Polymorphism in Object-Oriented Programming is an ability to create a property, a function, or an object that has more than one realization.

Polymorphism is an ability to substitute classes that have common functionality in sense of methods and data. In other words, it is an ability of multiple object types to implement the same functionality that can work in a different way but supports a common interface.

For example, function that expects a super class instance as an argument can work correctly with subclass instance as well, without the function needs to know about any of the subclasses types.

Let’s take a look at a real-life example of polymorphism. If you have learned how to drive one car, you’ll be able to drive any other car; it doesn’t depend on the make of car it’s configuration or inner implementation. It has the same driver interface.

The same in programming: if your code is able to work with one implementation of interface, it should work with another as well. Of course, it should have the same list of methods and properties.

In case of dynamic binding or late binding we don’t have to know the exact type. It’s enough to be sure that instance will be of some type or has some super class that contains needed functionality. In this case the exact behavior is determined at run-time. That important ability is a reason of using polymorphism which simplifies code in case when many objects have the same interface with different implementations.

Let’s consider the following code example. We would like to create a family of shape classes with common interface to work with each of them in the same way and be able to create more shape types in the future without updating a code that handles them.

For that we will create a parent class called Shape, and, for example, 3 child classes: Circle, Rectangle, and Triangle, with one method that will return shape area based on shape configurations. Also, we will add a code that works with instances of those classes.

So, here we have three classes that extend basic Shape class and provide different implementations of area method. Also, we have a method cumulateShapes that receives an array of shapes and returns cumulative area value of all passed shapes. The amount of various classes that implement Shape class has no influence on cumulateShapes; it’s enough that each of that class supports common interface provided by the parent class.

In the example above we have used inheritance to describe polymorphism behavior, but it is not critical. You can create a bunch of objects or classes that doesn’t have the same basic class but still support the same interface of methods and properties that will also cover that principle. As an example, we can create an object that doesn’t extend Shape class but still has a method area.

The program will still work correctly if we pass as square object into the cumulativeShape`s array parameter.

As you see, implementation of polymorphism in JS ES7 can often use other important OOP principles, especially inheritance, but still it is a separate concept and can be used without inheritance. Understanding of the matter enables you to provide efficient solutions to the communication between different parts of your system, makes your code cleaner and more readable. To understand it deeper and improve usage of polymorphism, I recommend that you get familiar with Liskov substitution and interface segregation SOLID principles. You can easily find enough information about it.
In the next article we are talking about Encapsulation.

--

--