Object-Oriented programming with Javascript
OOPS in Javascript: Why it is required?
The object-oriented programming refers to a paradigm in which structured, reusable pieces of code called objects are created, and its functionalities are borrowed by several other pieces of code. In most of the traditional programming languages, object-oriented programming is implemented with the help of Class
. In Javascript, however, OOP is implemented using Function
(Usage of ES6 provides class
model too, more on that later).
Prerequisites:
In javascript objects are the building blocks of our application. Everything translates into an object (Functions, Arrays, Strings, Objects). Since javascript already provides the prototype
attribute on every object, using this object-oriented programming can be achieved in javascript. On top of this, ES6 has now introduced a new way of implementing OOP in Javascript.
The 3 main valuable techniques object-oriented programming provides us are
- Inheritance: Objects can inherit methods and properties from other objects
- Encapsulation: Every object is responsible for handling a complete set of functionalities. Meaning, the object holds data and methods encapsulated inside it to perform all the operations required.
- Polymorphism: Objects can share the same interface, however, the way they are accessed defines its underlying functionality.
In javascript, Inheritance and Encapsulation are the two techniques that can be used under the hood of Object-oriented programming. This article will aim at explaining two ways in which OOP can be achieved in javascript.
Function-based inheritance and encapsulation
In the function-based inheritance, we define a constructor function and add the properties(methods and objects) which can be inherited by other constructors. Each constructor function contains all the private methods and variables, along with added inheritable properties to perform a given set of operations. The following code shows how object-oriented programming can be achieved using constructor methods.
function Vehicle(name, cost, engineType) {
this.name = name || '';
this.cost = cost || 0;
this.engineType = engineType || 'petrol';
}
Vehicle.prototype = {
constructor: Vehicle,
getEngineType: function () {
return this.engineType;
},
calculateEmi: function () {
return this.cost * 0.12;
},
setEngineType: function (type) {
this.engineType = type;
}
}
var vehicle1 = new Vehicle('Lamborghini Gallardo', 20000, 'petrol');
console.log(vehicle1.getEngineType()); // petrol
vehicle1.setEngineType('diesel');
console.log(vehicle1.getEngineType()); // diesel
The above example demonstrates just the encapsulation part of object-oriented programming. The constructor function Vehicle
has relevant properties and methods defined to work with its data. Let's use this constructor function to inherit its methods in another object and then go through all the pieces of code.
function Car(model, hasFuel, color, name, cost, engineType ) {
this.model = model || '';
this.hasFuel = hasFuel || false;
this.color = color || '';
this.name = name || '';
this.cost = cost || 0;
this.engineType = engineType || 'petrol';
}
Car.prototype = new Vehicle();
// Car.prototype = Object.create( Vehicle.prototype );
// This works too
Car.prototype.constructor = Car;
var lambo = new Car('gallardo', true, 'yellow', 'Lamborighini', 20000, 'petrol');
console.log(lambo.calculateEmi()); // 2400
The inheritance is created in the following ways:
- The
Vehicle
constructor function is created and it contains a list of properties on its object. - The
Vehicle
constructor function has sharable methods added to its prototype. - The
Car
constructor function is created which contains a list of properties on its object. -
The prototype of
Car
is pointed to the instance ofVehicle
constructor function. This can be done in several ways, two of the most common ones are highlighted here:Car.prototype = new Vehicle(); Car.prototype = Object.create( Vehicle.prototype );
-
The prototype of
Car
is overriden, andprototype.constructor
now points toVehicle
constructor function.Car.prototype.constructor = Car;
This line of code sets the prototype.constructor back to
Car
constructor function. - The new object created using the
Car
constructor function contains all the properties and methods present on theVehicle
constructor function. -
lambo.calculateEmi()
calls the function defined on Vehicle.prototype, the value ofthis
now points to the context oflambo
object.calculateEmi: function () { return this.cost * 0.12; }
In this method
this.cost
is now equal tolambo.cost
. The cost is calculated and returned.
One can notice that the assignment to the properties used in the Vehicle
object is repeated in the Car
object when we use the prototype for inheritance. There is another alternative method which works in a similar way to implement functional inheritance.
function Car(model, hasFuel, color, name, cost, engineType ) {
this.model = model || '';
this.hasFuel = hasFuel || false;
this.color = color || '';
Vehicle.call(this, [name, cost, engineType]);
}
var lambo = new Car('gallardo', true, 'yellow', 'Lamborighini', 20000, 'petrol');
console.log(lambo.calculateEmi()); // 2400
In the above example, instead of assigning the Car.prototype
object to a new Vehicle instance, we are calling the Vehicle
constructor inside our Car
constructor function, passing the reference of this
. To understand how Function.call(this, [...args]) work, please refer to : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call
- When a new object
lambo
is created, both Car and Vehicle are instantiated in the context oflambo
. Hence all the properties present on the constructor function are now accessible to the objectlambo
.
Class-based inheritance and encapsulation: ES6
In the Class-based inheritance, we use the class keyword provided by ES6. The class contains a constructor function where the variables are initialized. It also contains shared methods that behave similarly to the methods added to the prototype. The following code shows how object-oriented programming can be achieved using ES6 Class.
class Vehicle {
constructor(name, cost, engineType){
this.name = name || '';
this.cost = cost || 0;
this.engineType = engineType || 'petrol';
}
getEngineType() {
return this.engineType;
}
calculateEmi() {
return this.cost * 0.12;
}
setEngineType(type) {
this.engineType = type;
}
}
class Car extends Vehicle{
constructor(model, hasFuel, color, name, cost, engineType) {
super(name, cost, engineType);
this.model = model || '';
this.hasFuel = hasFuel || false;
this.color = color || '';
}
}
var lambo = new Car('gallardo', true, 'yellow', 'Lamborighini', 20000, 'petrol');
console.log(lambo.calculateEmi()); // 2400
This example is a replica of the above example demonstrated. However, it is implemented using class
. Let's go through the code and see what's happening.
- The class
Vehicle
is created. ES6 provides a separate function calledconstructor
which acts as the constructor function for the given class. If no constructor is defined, this will be an empty function. - The sharable methods are added to this
Vehicle
class. - The class
Car
is created. ES6 provides a functionsuper
which can be used to invoke the parent function. This is quite similar to usingCar.prototype = new Vehicle()
. It calls the parent function's constructor. - The new object
lambo
is created which contains all the properties ofCar
andVehicle
. Whenlambo.calculateEmi()
is called, it accesses the method present in theVehicle
class and gives the result.
To fully understand the concept of inheritance and implement it without running into any pitfalls, the concept of this must be mastered. This article has aimed at demonstrating some of the popular methods of implementing OOP in javascript and I am hopeful you understood at least the general concepts. Please use these patterns in your JavaScript applications and Happy coding.
Written by Aparna Joshi who works as a software engineer in Bangalore. Aparna is also a technology enthusiast, writer, and artist. She has an immense passion and curiosity towards psychology and its implications on human behavior. Her links: Blog, Twitter, Email, Newsletter