profile image

CODES REALM

A Software & Cloud Engineering Journal.

Quick Tags

C# / .Net

JavaScript / TypeScript

Azure

Kotlin / Java

Notes

Azure Certification Notes

Back to home

JavaScript OOP : Polymorphism

This post is part of a series of posts on JavaScript object-oriented programming. Link to the series are as follows:

This series is as follows:

  1. Pillars of Objected-Oriented Programming
  2. JavaScript Objects, prototype, constructor, & Object constructor
  3. Object Creation in JavaScript
  4. JavaScript OOP : Abstraction
  5. JavaScript OOP : Encapsulation
  6. JavaScript OOP : Inheritance
  7. JavaScript OOP : Polymorphism
  8. JavaScript OOP : Inheritance vs Composition

This post is a continuation of the object-oriented programming in JavaScript where we discuss polymorphism.

What is polymorphism ?

Polymorphism in the ability to exist and appear in many forms.

  • Derived objects or subclass may be treated as objects of a base class such as collections of arrays
  • Derived objects can override methods of a base object by providing their own implementations

Let's explain this concepts in JavaScript while building upon the Shape object and its derived objects from the inheritance post.

A Child object or subclass or derived object may be treated as a parent objects of a base class

Let's borrow some code from the inheritance post.


    function Shape(color, name){
        this.color = color;
        this.name = name;
    }

    Shape.prototype.draw = function(){
      console.log(`${this.name} with color ${this.color} is drawn!`);
    };


    //Circle Shape
    function Circle(radius, name, color){
        //Calling the base or parent class
        Shape.call(this, color, name);
        this.radius = radius;
      }

      //Circle inherit from Shape
      inherit(Shape, Circle);


    //Triangle Shape
    function Triangle(base, height, name, color){
        Shape.call(this, color, name);
        this.radius = radius;
      }

      //Triangle inherit from Shape
      inherit(Shape, Triangle);


      //Rectangle Shape
    function Rectangle(length, breath, name, color){
        Shape.call(this, color, name);
        this.radius = radius;
      }

      //Rectangle inherit from Shape
      inherit(Shape, Rectangle);


    function inherit(Parent, Child){
        Child.prototype = Object.create(Parent.prototype);
        Child.prototype.constructor = Child;
    }

Treating all kinds of shape as a Shape object yet still able to behave in the form of the different shapes.


    const shapes = [
        new Circle(10, 'Circle', 'red'),
        new Triangle(5, 10, 'triangle', 'black'),
        new Rectangle(10, 10, 'rectangle', 'blue')
    ]

    shapes.forEach(shape => shape.draw());

    //Circle with color red is drawn!
    //triangle with color black is drawn!
    //rectangle with color blue is drawn!

All the shapes object are now treated like a single Shape object while they behave differently.

Derived objects can override methods of a base object by providing their own implementations

This concept of having a child object overridding the parent's method is referred to as method overriding. Let's now implement method override for each of the child object of the Shape object by providing different implementation of the draw() method on each child object except the Circle object.


    function Shape(color, name){
        this.color = color;
        this.name = name;
    }

    Shape.prototype.draw = function(){
      console.log(`${this.name} with color ${this.color} is drawn!`);
    };


    //Circle Shape
    function Circle(radius, name, color){
        Shape.call(this, color, name); //Calling the base or parent class
        this.radius = radius;
      }

      //Circle inherit from Shape
      inherit(Shape, Circle);


    //Triangle Shape
    function Triangle(base, height, name, color){
        Shape.call(this, color, name);
        this.base = base;
        this.height = height;
      }

      //Triangle inherit from Shape
      inherit(Shape, Triangle);

      Triangle.prototype.draw = function(){
        console.log(`From Triangle override: ${this.name} with color ${this.color} is drawn!`);
      }


      //Rectangle Shape
    function Rectangle(length, breath, name, color){
        Shape.call(this, color, name);
        this.length = length;
        this.breath = breath;
      }

        //Rectangle inherit from Shape
        inherit(Shape, Rectangle);

      Rectangle.prototype.draw = function(){
        console.log(`From Rectangle override: ${this.name} with color ${this.color} is drawn!`);
      }




    function inherit(Parent, Child){
        Child.prototype = Object.create(Parent.prototype);
        Child.prototype.constructor = Child;
    }

    const shapes = [
        new Circle(10, 'Circle', 'red'),
        new Triangle(5, 10, 'triangle', 'black'),
        new Rectangle(10, 10, 'rectangle', 'blue')
    ]

    shapes.forEach(shape => shape.draw());
    //Circle with color red is drawn!
    //From Triangle override: triangle with color black is drawn!
    //From Rectangle override: rectangle with color blue is drawn!

The Triangle and Rectangle objects now have their own implementation of the draw method which is slightly different from their ancestor's implementation. The way this works in JavaScript is that when a method or property is invoked on an object, the property is first looked up on the object and if not found, its prototype (parent) is checked for the property and if not found, it continues to the next prototype up the chain until it's found and if eventually, it's not found, the JavaScript engine then errors out.

This concludes the post on polymorphism in JavaScript object oriented programming

Happy coding...

Credits:
Image by LOISLEARNS : https://loislearns.com/2016/08/30/polymorphism/

JavaScript OOP : Inheritance