Polymorphism
Tags: beginners, javascript
Published: 2020-07-09 05:51:26

### Introduction

`Polymorphism` is a term used with constructor function instantiations to give multiple functions a tree of sorts, each sharing the previous's properties and methods.

It's primarily used to cut down on code in Object-Oriented Programming to make sure the working experience is streamlined, giving a "write less, do more" attitude if you will.

While it's a simple concept on the surface, it isn't uncommon to see a newer coder get stuck on the "coding magic" that is polymorphism, and even instantiation as a whole. This blog will, by the end of it, help you on your way to making all kinds of constructors for all kinds of things.

### How does it work?

When we instantiate a constructor function, we primarily have two choices in syntax in JavaScript<sup>1</sup>: `ES5` and `ES6`. `ES5`  is more familiar to most coders, as it doesn't take away any of the syntax that has been since JavaScript's creation. `ES6` is functionally identical, but it adds a lot of syntactic sugar to make it much more convenient to look at.

For the examples, we will be using `ES5` syntax.

For `ES5`, when we want to call what's called the `superclass`, or its "parent" class, We do this with the conveniently-named `.call(this)`. `this` is called for the context, as we want the constructor itself to be instantiated with the parent class. Also don't forget to pass in any relevant arguments your subclass needs defaulted by the superclass!

Also keep in mind that because we call the superclass on the subclass itself, that means the `prototype` is also copied. Make sure to copy that with `Object.create(<superclass>.prototype)` to the proper constructor name before you move on. Same goes with the `prototype.constructor` specifically. Remember, you *copied* the proto, so you should make sure all names are relevant to their context.

```js
// Superclass declaration
const Auto = function(owner) {
  this.owner = owner;
};
Auto.prototype.drive = function() {
  /* {...} */
};

// Subclass declaration
const Car = function(make, model, owner) {
  // Calling the superclass, Auto, with .call(this), also passing in the owner param.
  Auto.call(this, owner);
  this.make = make;
  this.model = model;
};
// Copying the proto...
Car.prototype = Object.create(Auto.prototype);
// Changing the constructor function. This is important for when the call stack needs 
// to refer back to something. As with everything, you should ALWAYS keep information 
// relevant.
Car.prototype.constructor = Car;
```

`ES6` however, doesn't need to do that whole `Object.create()` thing after the base function. In fact, because `ES6` has completely different syntax, you do things just as differently. When you define your `constructor() {}`, you start by calling the superclass with the aptly named `super()` function, once again passing in the relevant parameters.

On top of that, instead of doing `<superclass>.call(this, ...args)`, to define *what* the superclass is, you use yet another keyword that `ES6` added in, that being `extends`. You place it after your class name, but before the code block.

```js
// Superclass
class Auto {
  constructor(owner) {
    this.owner = owner;
  }
  drive() {
    /* {...} */
  }
}

// Subclass
// Notice how we add "extends Auto" after the normal naming.
class Car extends Auto {
  constructor(make, model, owner) {
    // super(owner) is basically <superclass>.call(this, owner). In this case,
    // <superclass> is Auto.
    super(owner);
  }
  // And we don't need anything else. "extends" does that jumble of mess below the
  // base for us.
}
```

And if you're feeling extra brave, know that subclasses can also have their own subclasses, same rules applied as before. This makes a "tree" of call chaining, calling the more and more general parent classes to get back all of the properties that should be owned by ALL subclasses, or to hardcode certain parameters, depending on what you're trying to do.

```js
class Car extends Auto {
  constructor(make, model, owner) {
    super(owner);
    this.make = make;
    this.model = model;
  }
}

class FordCar extends Car {
  // Notice how the parameters for the constructor get shorter the more hardcoded things
  // you enter.
  constructor(model, owner) {
    super('Ford', model, owner);
    this.model = model;
  }
}

class FordFocus extends FordCar {
  constructor(owner) {
    super('Focus', owner);
  }
}
// This could go on for a while, but you get the idea.
```

```js
/*
  And in case you need a bit more of a visual...
  FordFocus('James') is calling
  FordCar('Focus', 'James') which is calling
  Car('Ford', 'Focus', 'James').
*/
```

### Conclusion

`Polymorphism` is a fairly simple concept primarily in Object-Oriented Programming used to create a "tree" of constructors, to cut down on the code required to write, which seems menial in small examples like these, but can be a lifesaver in much bigger projects. And understanding this concept thoroughly allows you to make your code cleaner, shorter, and with much less hassle than if you were to do it separately.

##### Superscript References

1. JavaScript is not a primarily Object-Oriented Programming language, and similarly, the term `polymorphism` is not reserved to it. It's a concept that's found in languages such as Python, C/#/++, and Java, who focus more heavily on OOP given their structure.