Object-oriented programming (OOP) is a programming paradigm that organizes code around objects. Objects are self-contained entities that contain both data and code. This makes code more reusable, maintainable, and scalable.
While this style of programming has been adopted by so many languages, we'll be focusing on its application in JavaScript.
THE FOUR CORE CONCEPTS OF OOP
Encapsulation
Abstraction
Inheritance
Polymorphism
I'll be giving a detailed explanation of these core concepts below.
But note, the pre-requisite for studying OOP is that you must at least have the basic knowledge of Objects in Javascript.
If you don't know or you just need a refresher, I wrote a piece on it, you can check it out HERE.
ENCAPSULATION
Before the introduction of OOP, we used the traditional concept of programming which is fondly called procedural programming.
This style of programming involved just data types and functions which act on them.
The problem with this style of programming is the interdependency between the functions.
While this might not be a problem for a small codebase, it might be very disturbing for a larger one.
One line of change can break your whole code, coupled with the redundancy that comes from copying and pasting so many functions and variables and the bulk parameters in functions.
With OOP, we combine groups of related data types and functions into units which are called objects.
This concept is referred to as encapsulation.
Let's visualize this using the example below. In our example, we will first use the procedural method and then the OOP style of encapsulation. Just so we can highlight the difference between them.
Procedural Method
let baseSalary = 30,000;
let overtime = 10;
let rate = 20;
function getWage(baseSalary, overtime, rate) {
return (baseSalary+overtime+rate);
}
OOP Method Since these values are closely related, we will encapsulate them in an object like so:
let employee = {
baseSalary: 30,000,
overtime: 10,
rate: 20,
getWage: function() {
return this.baseSalary+(this.overtimme*this.rate);
}
}
The this
keyword is used as a reference to the object that executes a piece of code. In this case, it refers to the employee object.
As we can see above the OOP is a more concise way of programming.
ABSTRACTION
The concept of abstraction is to handle complexities in a code by hiding unnecessary details from the users and showing only the essential attributes.
Think of this as making a coffee. To make a coffee with a coffee machine, you only need to know the right buttons to press and then you wait for your coffee. You don't care how the coffee machine does this, in the end, you only want your coffee.
The concept of abstraction is applied here, all the unnecessary details and mechanics are hidden inside the machine away from the user and the necessary details like buttons are displayed.
Abstraction in OOP is achieved using the concept of closures. Closure is the idea of determining that variables and methods are accessible by an inner function in an object.
Let's visualize this using the example below:
function circle (radius) {
let defaultLocation = {x: 0, y:0};
let computeLocation = function (factor) {
// code to be executed
}
this.draw = function () {
computeLocation(0.1);
console.log("draw");
}
}
The variables defaultLocation
and computeLocation
is within the scope of the circle function, but it is within the closure of the draw function.
This is an example of abstraction. The defaultLocation
and computeLocation
is only accessible inside the object, outside the object, users cannot access it's properties or methods.
Let's try this using another example.
function person(name, age) {
let personName = name;
let personAge = age;
let notAccessible = function() {
return (`Your name is ${personName} and you are ${personAge} years old`);
}
this.accessible = function(){
return (`Your name is ${personName} and you are ${personAge} years old`);
}
}
The personName
, personAge
and notAccessible
properties and methods cannot be accessed outside the person
object. This means it has been hidden from the 'user' since it's unnecessary in this case.
If we want to abstract a property or method, we define it using let
, or const
because these keywords are used to create private variables. While we use this
keyword is used to define methods and properties that can be used outside of the object.
Classes and Constructors.
A class is a blueprint or template for creating objects. Javascript is a prototype-based language and this means it does not have classes. It defines its behavior using the constructor function and then reuses its prototype.
A constructor is a method that is used to define the properties and methods of an object created within a class.
Let's initialize an object using a class below:
class Car {
constructor(name, year) {
this.name = name;
this.year = year;
}
}
We can now use this class to create various objects with properties of name
and year
like so:
let myCar = new Car("Ford", 2014);
let yourCar = new Car("Benz", 2014);
let theirCar = new Car("Toyota", 2014);
myCar
object has a name of "Ford" and a year of "2014". I hope you understand this concept.
To create a class inheritance, we use the extends
keyword.
class Car {
constructor(brand) {
this.carname = brand;
}
}
class Model extends Car {
constructor(brand, mod) {
super(brand);
this.model = mod;
}
}
let myCar = new Model("Ford", "Mustang");
The super
keyword here refers to the parent class and by calling it, we call the parent's constructor method and get access to its properties and methods.
INHERITANCE
This is a concept that allows us to eliminate redundancy in a code. It does this by having an existing object known as the parent object that defines the core properties of an object and then have other objects inherit properties and methods from the original object.
Let's visualize this using animals. In a group of animals like lions, cats, dogs. We can declare different objects for them like so:
let lions = {
limbs: 4,
eyes: 2,
height: "222m"
}
let cats = {
limbs: 4,
eyes: 2,
height: "100m"
}
let dogs = {
limbs: 4,
eyes: 2,
height: "150m"
}
As we can see, the above format is redundant and time-consuming. We can clean up this code using inheritance. In this manner, since these objects have similarities, we can make a general object and then have others inherit from it.
Let's do this!
class Features {
constructor (limbs, eyes) {
this.limbs = limbs;
this.eyes = eyes;
}
}
class Animals extends features {
constructor(limbs, eyes, height ) {
super(limbs, eyes)
this.height = height
}
}
let dog = new Height(4, 2, " 150m ");
We can see that we have successfully created the dog object that has the limb eyes and height properties. We can create 100 different objects using this method.
Go ahead and create the lion and cat object using this format.
POLYMORPHISM
As the name suggests, polymorphism means many forms. Poly means "many" and morphism roughly translates to "forms". It helps us avoid long if...else
and switch
statements.
This concept simply implies that while the same process and methods can be used for different objects, each object possesses the unique ability to override shared methods with a more specific implementation.
Polymorphism uses the concept of inheritance to achieve this, multiple objects will have the same methods but possess different implementations. Let's use the example below to visualize this.
class Vehicle {
constructor(name) {
this.name = name;
}
say() {
console.log("I am a " + this.name)
}
}
let myCar = new Vehicle('Bugatti');
let yourCar = new Vehicle('Toyota')
myCar.say(); // I am a Bugatti
yourCar.say(); // I am a Toyota
From the example above, both objects will have the same method and will both return the same string format from the say() method in the Vehicle class.
With polymorphism, we can alter the method by first myCar
object like so
class Vehicle {
constructor(name) {
this.name = name;
}
say() {
console.log("I am a " + this.name)
}
}
class Car extends Vehicle {
say() {
console.log("I used to be a " + this.name)
}
}
let myCar = new Car('Bugatti');
let yourCar = new Vehicle('Toyota')
myCar.say(); // I used to be a Bugatti
yourCar.say(); // I am a Toyota
This is known as Method Overriding and it allows multiple objects to have the same methods but different implementations.
As we have seen, Object Oriented Programming is a very effective and vital programming concept.
Let me know what you think in the comment section, I'm open to questions, ideas and suggestions.
If you found this insightful, check out my other articles and don't forget to share it with your friends.
Happy coding 💫