Object-Oriented Programming In JavaScript - 1

What is Object Oriented Programming(OOP)

Object-oriented programming is a programming paradigm(i.e style of writing code) based on the concept of objects. OOP was developed to organize code, to make it more flexible and easier to maintain(avoid "Sphegatti Code").

What is Object

In programming, we're trying to solve real-world problems through our applications. we use objects to represent any real-world entity(e.g. Student, Person, Car, etc).

An object may contain data and methods(behaviors), By using objects we pack data and corresponding behaviors into one block.

The 4 Fundamental OOP Principles

  1. Abstraction: Abstraction means displaying only essential information and hiding the details.

  2. Encapsulation: The process of wrapping properties and functions within a single unit is known as encapsulation.

  3. Inheritance: JavaScript Objects inherit Objects i.e. certain features (property and methods) of one object can be reused by other Objects.

  4. Polymorphism: Polymorphism means the same function with different signatures is called many times.

We will implement these principles in the next part of this series.

OOP In JavaScript

JavaScript is a prototype-based object-oriented language. In JavaScript, OOP works differently from languages like C++, Java, etc.

In JavaScript, there is no concept of "class", we have only objects**.** Everything works around "Prototypes". In javascript, we define methods(behaviors) using a constructor function and reuse them using prototypes and prototypal inheritance.

Note: ES6 classes, also implement Prototypal Inheritance under the hood. Don't confuse javascript classes with traditional classes (e.g. C++ and Java).

Prototypal Inheritance/Delegation

The prototype contains methods that are available to all objects linked to that prototype or we can say that behaviors are delegated to the linked prototype object.

const num1 = [1, 2, 3];
const num2 = num1.map(n=>n*2);
//map method is on Array.prototype, which is the prototype of all array objects that's why num1 array is able to access map() method.

3 Ways Of Implementing Prototypal Inheritance In JavaScript

  1. Constructor Function: It is a technique to create objects from a function, This is how in-built objects like Arrays, Maps, Sets, etc are implemented.

  2. ES6 Classes: It is a modern alternative to constructor function syntax. It is only a "Syntactical Sugar". Behind the scenes, ES6 classes work exactly like constructor functions. ES6 classes don't behave like classes in other languages.

  3. Object.create(): The easiest and the most straightforward way of linking an object to a prototype object.

Constructor Function

The constructor function is just a regular function. The only difference between a regular function and a constructor function is, we call the constructor function with the "new" keyword.

//Creating Constructor Function
const Person = function(fullName, birthYear){
    //Some code
}

//Calling constructor function
new Person("Akash", 2003);

When we call a function using the "new" keyword, There are four steps that happen behind the scenes,

  1. A new empty object is created;

  2. The function is called and this keyword gets set to that empty object;

  3. Object linked to a prototype;

  4. The function automatically returns that object.

Let's complete our Person example,

//Creating Constructor Function
const Person = function(fullName, birthYear){
    //Instance Properties
    this.fullName = fullName;
    this.birthYear = birthYear;
}

//Calling constructor function
const akash = new Person("Akash", 2003);
console.log(akash) // {firstName: "Akash", birthYear: 2003}

//Now we can create as many as objects
const john = new Person("John", 2000);
console.log(john.fullName); //John

Now, the Person constructor function is a blueprint to create an object/instance of the Person type.

In Classical OOP, we create objects/instances from a class.

In JavaScript OOP, we create objects/instances from a constructor function.

How to add instance methods?

Should we do like this?๐Ÿ‘‡

const Person = function(fullName, birthYear){
    //Instance Properties
    this.fullName = fullName;
    this.birthYear = birthYear;

    //Never Do This
    this.calcAge = function(){
        return 2023 - this.birthYear;
    }
}
const akash = new Person("Akash", 2003);
const john = new Person("John", 2000);

No, we never do this. when we create objects from a constructor function every object gets its copy of properties, but if we take a closer look at this method, the code of this method is going to be the same for all the objects created by this Person constructor function, so why we are creating a copy of this method again and again for every object. This is not cool, right?

Then how should we do it?

Here comes "Prototype" in action. Every JavaScript function automatically have the property called prototype.

Every object created by a certain constructor function will get access to all the methods and properties that we define on the constructor's prototype property.

const Person = function(fullName, birthYear){
    //Instance Properties
    this.fullName = fullName;
    this.birthYear = birthYear;
}

//Now calcAge function will be created only once
Person.prototype.calcAge = function(){
    return 2023 - this.birthYear;    
}
const akash = new Person("Akash", 2003);
const john = new Person("John", 2000);

console.log(akash.calcAge());//20
console.log(john.calcAge());//23

Here, objects created by the Person constructor function inherit all the methods defined in its prototype property. --> "Prototypal Inheritance"

Each object has a special property called __proto__. when we create an object from the Person constructor function it creates __proto__ property inside that object and sets its value to Person.prototype.

Here is one thing to understand the Person.prototype is not the prototype of the Person, instead it is the prototype of objects created using the Person constructor function. The person has the property prototype which has some methods which are accessible to all the objects created by the Person constructor function.

console.log(Person.prototype === akash.__proto__) // true
console.log(Person.prototype.isPrototypeOf(akash)) // true

console.log(Person.prototype.isPrototypeOf(Person)) //false

This is how JavaScript knows that a particular object is connected to the Person.

This is how we implement Prototypal Inheritance in JavaScript.

This was part one of the OOP in JavaScript series.

Thank you for reading!โ™ฅ

0
Subscribe to my newsletter

Read articles from Akash Deep Chitransh directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Akash Deep Chitransh
Akash Deep Chitransh

I am a front-end developer, currently working at TCS.