Object orientated programming in JS

December 30, 2018

4 min read

Oop

Photo by Hal Gatewood on Unsplash

In Object orientated programming you group data and methods into a single entity called class and create different instances of the class called objects. These objects will have different data. Inheritance is another OOP feature, it allows us to reuse code by creating parent and child classes. Parent class has code which is common to all the children. Children are a specialization of the parent.

Javascript’s inheritance model

Javascript follows a prototype bases inheritance model. The prototype is a property that a JS engine will add to the function. This prototype object intern has constructor property by default. To check the properties available on the prototype you can use Object.getOwnPropertyNames(functionName.prototype) to check what properties exist on a prototype.

Creating a class and its instance

Let’s first take a look at how you create a specific class object in JS. To create an object you need to make use of a constructor function. You can use constructor function to get objects of the specific type. You must have already seen new keyword used in new Array(), new Date(). In the following case, we are creating a constructor function for Transport type. The convention is to name your constructor function as you would name class.

function Transport(mode, travelSpeed, ticketCost) {
  this.mode = mode
  this.travelSpeed = travelSpeed
  this.ticketCost = ticketCost
}

let bus = new Transport('Road', 'Slow', 'Cheap')
console.log(bus)
// Output: { mode: "Road", travelSpeed: "Slow", ticketCost: "Cheap" }

So here we created a constructor function, that creates an object of type Transport.

To check if an object is an instance of a class using the ‘instance of’ operator.

bus instanceof Transport
// Output: true

You can also check the properties on the protype object.

console.log(Object.getOwnPropertyNames(Transport.prototype))
// Output: Array [ "constructor" ]

Adding mehods to the class

When working with classes we should methods on the prototype, since this way we can change the method on the prototype and will reflect in all the instances.

Transport.prototype.showInfo = function() {
  console.log(this.mode, this.travelSpeed, this.ticketCost)
}
bus.showInfo()
// Output: Road Slow Cheap

If you check the prototype property of transport now you will see the method that we just added.

console.log(Object.getOwnPropertyNames(Transport.prototype))
// Output: Array [ "constructor", "showInfo" ]

Creating a child class

Now let’s create a separate type of class for Bus, as this object which will have properties which are not required not common to the Transport class.

function Bus(mode, travelSpeed, ticketCost, busType) {
  Transport.call(this, mode, travelSpeed, ticketCost)
  this.busType = busType
}

let interCityBus = new Bus('Road', 'Slow', 'Cheap', 'Sleeper')
console.log(interCityBus)
// Output: { mode: "Road", travelSpeed: "Slow", ticketCost: "Cheap", busType: "Sleeper" }

In the above example, we have created a child-parent relationship by calling the Transport constructor function from within the Bus constructor function. Transport.call() is like a super() operator call.

Inheritance is not completely achieved here though, let’s check the prototpe property of the bus class

console.log(Object.getOwnPropertyNames(Bus.prototype))
// Output:  Array [ "constructor" ]

This does not have the methods which were defined on the parent. To have the properties from the parent you need to merge the child and parent prototype, it is explained very nicely and in detail in this MDN post, and this post on Digital Ocean communiy. To know more about prototypes in JavaScript read these posts (JavaScript Prototype in Plain Language, Prototypes in JavaScript). Also you can overide methods in the children by assigning a value to it in the prototype of the child class.

Easier way to work with classes

Working with prototypes can become a bit tedious and confusing. There is another way to tackle inheritance though, ES 2105 brought new syntax to create a class. Internal inheritance mechanism remains the same though. Let’s convert the above example to a class-based solution.

class Transport {
  constructor(mode, travelSpeed, ticketCost) {
    this.mode = mode
    this.travelSpeed = travelSpeed
    this.ticketCost = ticketCost
  }

  showInfo() {
    console.log(this.mode, this.travelSpeed, this.ticketCost)
  }
}

class Bus extends Transport {
  constructor(mode, travelSpeed, ticketCost, busType) {
    super(mode, travelSpeed, ticketCost)
    this.busType = busType
  }
}

let cityBus = new Bus('Road', 'Slow', 'Cheap', 'Seating')
cityBus.showInfo()

There we have it, doesn’t it look neat and clean? We made use of super() operator to pass values to the constructor of the parent class. Also, this way we don’t need to merge the prototypes of parent and base class as it is handled by Javascript for us. If we wanted to change the behavior of showInfo() method we can do it simply redefining it in the child class.

class Bus extends Transport {
  constructor(mode, travelSpeed, ticketCost, busType) {
    super(mode, travelSpeed, ticketCost)
    this.busType = busType
  }

  showInfo() {
    console.log(this.mode, this.travelSpeed, this.ticketCost, this.busType)
  }
}

let cityBus = new Bus('Road', 'Slow', 'Cheap', 'Seating')
cityBus.showInfo()

You don’t always have to set all the properties inside the constructor, at times you might want to set and read only particular value, you can read about getters and setters here.

If you like this post do share it, follow me to keep updated with my posts :).