09 February 2015

Introduction to Polymorphism

Polymorphism could be defined as an object's ability to manifest in different forms. The abstract notion of polymorphism manifest as the concrete application of subclassing. A class works great when you want to create a fleet on similar objects. Polymorphism allows us to subclass in order to augment different behavior onto different objects.

Functional Inheritance

Functional inheritance can be used with functional instantiation (aka: Factory Pattern) or shared functional instantiation. Functional inheritance is when you instantiate an object inside a function, and then augment that object with special properties before returning it.

function Shape(width, height) {
  var shape = {};
  shape.width = width;
  shape.height = height;
  return shape;
}

function Square(width, height) {
  var shape = Shape(width, height);
  shape.size = this.width * this.height;
  return shape;
}

square = Square(100, 100);
>>>Object {width: 100, height: 100, size: 10000}

We called the Shape factory and received a Shape object in return. We then augmented it with a size property and returned the augmented object.

Pseudo-classical Inheritance

Pseudo-classical inheritance is used with pseudo-classical instantiation (aka: Constructor Pattern). There are two different things that need to be inherited when using the pseudo-classical style. Firstly, you need to inherent properties from within the constructor. Secondly, you need to inherent properties from ConstructorName.prototype. Additionally, you also need to manually set the subclass's constructor property. The subclass inherents it's prototype from the superclasses prototype, this works fine but it has the unfortunate side effect of destroying the reference the subclasses prototype constructor property has to itself. We need to set the subclasses constructor property manually as a result.

function Fruit(sweetness, freshness, organic) {
  this.sweetness = sweetness;
  this.freshness = freshness;
  this.organic = organic;
}

function Apple(sweetness, freshness, organic) {
  Fruit.call(this, sweetness, freshness, organic);
  this.color = "red";
  this.name = "apple";
}

Notice when we use pseudo-classical inheritance that the line Fruit.call(this, sweetness, freshness, organic); is what is doing the heavy lifting here. All we need to do is call the superclass Fruit from within subclass Apple for inheritance to occur. The reason we do not need to set any variables explicitly is because our call to Fruit is occurring in the context of Apple. Therefore when this is used in superclass Fruit it is actually referring to the object that is being instantiated in Apple since this refers to the object being created when using the Constructor pattern.

As stated previously, on top of calling Fruit.call(this, sweetness, freshness, organic); we also need to set inheritance in their Prototype chains correctly and set the subclasses constructor property manually on it's prototype.

Apple.prototype = Object.create(Fruit.prototype);
Apple.prototype.constructor = Apple

If we do not manually set Apple.prototype.constructor = Apple then the constructor property will be lost due to inheritance overriding it. We would then get weird behavior when using functionality like instanceof.