Object Oriented Programming in JavaScript: Is Javascript Object Oriented?

quiz
Challenge Inside! : Find out where you stand! Try quiz, solve problems & win rewards!

Overview

Is JavaScript an Object-oriented language? It uses objects and follows the principles of OOP, but it does this using pure functions, which is a property of the functional programming paradigm (FP). JavaScript follows both OOP and FP and is actually a procedural language.

Scope of the Article

  • The article starts by explaining which principles a language needs to follow to be said to be an OOP language.
  • Then, it answers the common question - "Is JavaScript object-oriented language?"
  • This article explains objects, classes, encapsulation, and inheritance with examples.
  • You will see how classes and objects can be created in JavaScript.
  • Objects in OOP have to have relationships, which can be through aggregation, composition, or association. All three are explained in detail.
  • We can create classes in JavaScript. Still, JavaScript is not said to be a complete object-oriented language. Understand why!

What is OOP (Object-oriented Programming)?

OOP is a programming paradigm that believes in grouping data (properties) and methods (actions) together inside a box. It demonstrates the pattern of real-world objects.

Note: JavaScript is not an object-oriented language. Neither is it completely a functional language. JavaScript is a prototype-based procedural language. It supports both functional and object-oriented patterns of programming.

There are two types of OOP languages:

1. Class-Based languages like JAVA, C++.
2. Prototype-Based languages like JavaScript.

But what makes a language an OOP-based programming language?

There are four primary pillars of Object-Oriented Programming. Any piece of code following the OOP paradigm must adhere to these basic rules of Object-orientation.

Features of an Object-Oriented Language

There are four rules or main pillars of Object-oriented programming language. This defines how the data and actions associated with the data; are organized using code.

four rules of oop language

Let us discuss all four of them in detail below.

Object

What is an object?

An object is a data structure containing properties and methods. Consider a student. A student will have characteristics like name, roll number, and class, and he will perform an action, let's say, giving an exam. In object-oriented programming, these characteristics are called data variables. These actions are called data methods.

We create a class called Student and then create instances of this class. These instances are called Objects. Hence, an object is a real instance of a class. Class is nothing but a prototype/blueprint.

Example: John Smith is an instance or object created using the class - Student.

object of oop language

Classes

A class defined the blueprint of the object. It demonstrates all characteristics its instance can have and all functions/actions it can perform.

For example, A class named Student defines all the data variables (characteristics) and data methods (actions) a student can hold, and the instances to it will hold the actual values. "John Smith" is one of the objects/instances created from the Student class. It has:

Name - John Smith
Roll number - 23
Section - 10A

Hence, a class is a template or a blueprint, whereas an object is the real instance of that class. Hence, a class can have many objects. Exactly how there can be a lot of instances of students in a school.

Note: Since JavaScript is not an OOP language but is a prototype-based language, it does NOT have classes. Instead, it defines behaviors using constructor functions and then reuses them using the prototypes. We'll see this in detail in later sections.

Encapsulation

Encapsulation wraps the data variables and data functions/methods together inside a single box/unit. This pillar of oops ensures that oops classes and object resembles real-world objects. In encapsulation, we group data and actions together so that data can be secured.

Note: Encapsulation and Abstraction are two different concepts. Encapsulation means grouping data variables and functions together. Whereas abstraction means hiding data.

Encapsulation in JavaScript

Consider this example:

In banks, all the cash is kept in lockers, and only the cashier can deal with the lockers. Take this as a box, with the cashier and the locker in it. An ordinary person visiting the bank does not know anything about lockers. He cannot visit his locker to deposit the resources himself, or he does not know how much cash is there in the lockers. The cashiers and the lockers are encapsulated together. This side of the cash window is a sort of abstraction for a commoner visiting the bank. The lockers hold the data for the bank, and the cashiers have access to all the actions which can be performed on that data.

This abstraction helps keep the bank data and resources safe and helps make the process uniform. This is the basic idea behind the following encapsulation in OOP.

Inheritance

We can create classes in JavaScript using all the functionality from another class, which is then called its parent class. The child class will contain all the data variables and data methods, and we can add more to it.

Basically, inheritance empowers us to reuse code efficiently. We can implement inheritance in JavaScript using the extends keyword.

Have a look at this example:

Inheritance

This example defines a class Person by defining the 'data variables' and 'data methods' corresponding to the class Person. Since we know that Student and Teacher possess all the properties of the class Person, we can simply inherit the features (or data variables) and action (or data methods) into them, and add more as well (The underlined properties are added to the children classes).

This is how this will be implemented:

class Person { 
    constructor(name) {
        this.name = name;
    }

    welcome() {
        console.log(`Hello ${this.name}`);
    }
}

// 'extends' is used to inherit from parent class
class Student extends Person {
    constructor(name, rollNo){
        
        //'super' calls the parent constructor
        super(name)
        this.rollNo = rollNo
    }
}

// 'extends' is used to inherit from parent class
class Teacher extends Person {
    constructor(name, teacherID){
        
        //'super' calls the parent constructor
        super(name)
        this.teacherID = teacherID
    }
}

let student1 = new Student('Jack');
student1.welcome();
// Student class now has all the data variables and data actions defined in its parent class, i.e. Person, plus roll number.

The super keyword is used to call the parent constructor. When we make an instance for the Student class, its constructor calls the constructor of the parent class, i.e. of Person class.

Note: The inherited data variables and data methods can be overwritten. This is called Method Overriding. We can override the inherited data member by simply creating another with the same name in the child class and adding a new body to it.

The example below shows how method overriding is implemented.

class Person { 
    constructor(name) {
        this.name = name;
    }

    welcome() {
        console.log(`Hello ${this.name}`);
    }
}

// 'extends' is used to inherit from parent class
class Student extends Person {
    constructor(name, rollNo){
        
        //'super' calls the parent constructor
        super(name)
        this.rollNo = rollNo
    }
    welcome(){
        console.log(`Hello ${this.name}`)
        console.log("You're a Student")
    }
}

let student1 = new Student('Jack');
student1.welcome();

Output:

Hello Jack
You're a Student

Is JavaScript Object-Oriented?

We need to understand the difference between OOP and Prototype-based programming, before finding the answer to this common question - ' Is JavaScript Object-oriented?'.

  • Object-Oriented Programming (OOP) The object-oriented paradigm keeps data and actions grouped together inside classes. In OOP, we create classes and then create their instances called objects.

  • Prototype-based Programming In Prototype-based programming, we derive objects from other already existing objects.

Prototype-based Programming

Note: Prototypes are the mechanism by which JavaScript objects inherit features from one another. --MDN Docs

JavaScript is a Prototype-based programming paradigm. It is not an OOP language. But it has support for it. It has the class keyword, which is just a syntactic sugar over prototypes. We actually create prototypes in javascript, and not classes. The class keyword is there to make javascript look like an OOP language.

Everything in JavaScript is an object. If you create an array, and then console it, you will find various key value pairs inside it, for example, you'll find the length property, which we never defined.

Prototype based programming paradigm

See, an array is also an object in JavaScript. Similarly, everything in JS is an object. Everything we define in javascript, be it an array, or a function, it extends the functionality from the prototype object.

Hence, JavaScript is a prototype-based language.

What is an Object in JavaScript?

As already explained, an object is a data structure containing properties and methods as key-value pairs in it. But how do we create one? Let's see. There are three ways to create one. We'll be discussing each one of them in detail.

Using an Object Literal

We can simply create an object, by putting in the key value pairs for the object. The data variables can simply have a number, a string, an array or an object as its value. A data function has a functions as its value.

Let us take a look at an example:

const student = {
    first_name: 'Mary',
    last_name: 'Green',
    display_full_name: function(){
        return `${this.first_name} ${this.last_name}`
    }
}

console.log(student.display_full_name());

Output:

Mary Green

This way of creating an object is hard-coded. What if we want to create objects for 100 users having the same three data members - first_name, last_name, and display_full_name? We'll have to write the whole object 100 times. So, what's better?

Note: this keyword is used to refer to the current object. To read more about this keyword, read this article for in-depth explanation.

Using an Object Constructor

We can create an object prototype and then create 100 instances for the same. Using Object Constructor is one way of doing this.

Let's see.

//Creating a constructor function
function student(first_name, last_name){
    this.first_name = first_name,
    this.last_name = last_name,
    this.display_full_name = function(){
            return `${first_name} ${last_name}`;
        }
}

//Creating instances for the constructor function
const student1 = new student("Mary", "Green");
const student2 = new student("Lary", "Smith");

console.log(student2.display_full_name());

Output:

Lary Smith

Using Object.create() Method

This is another method for creating objects. Simply create an object and create instances using the Object.create() method.

Let's see an example:

//Creating an object
const student = {
    first_name: 'Mary',
    last_name: 'Green',
    display_full_name: function(){
        return `${student.first_name} ${student.last_name}`
    }
}

//Creating an instance for the student object
const student1 = Object.create(student);

//Updating the last name
student1.last_name = "Smith";

console.log(student1.display_full_name());

Output:

Mary Smith

No Classes in JavaScript

JavaScript is a prototype-based language, and it doesn't have classes in it. We define the templates for objects using constructor functions or prototypes.

But JavaScript does have support for the class keyword. How can we say that classes cannot be created in JavaScript?

The keyword class in JavaScript is actually a syntactic sugar over the prototype-based inheritance, which is already present and supported in JavaScript. JS provides it so that the object creation aligns with other object-oriented languages where the creation of classes is supported.

ES6 Classes

Let's look at the ES6 way of defining classes, using the class keyword and then we'll see how classes were defined traditionally.

//Defining the class
class Student{
    constructor(first_name, last_name){
        this.first_name = first_name,
        this.last_name = last_name
    }
    display_full_name = function(){
        return `${first_name} ${last_name}`
    }
}

//Creating instances using the `new` keyword
const student1 = new Student("Mary", "Green");
const student2 = new Student("Lary", "Smith");

This way, we create a class using the class keyword. Define constructor function and all the other data functions inside the class declaration function. Then we create instances for this class using the new keyword.

Note: The new keyword binds the this keyword to the object. Hence, we should always create instances using the new keyword.

Traditional Way of Class Simulation

This is how classes were defined before JavaScript started supporting the class keyword. That is before ES6 came up.

function Student(first_name, last_name){
    this.first_name = first_name
    this.last_name = last_name
}
Student.prototype.display_full_name = function(){
    return `${this.first_name} ${this.last_name}`
}
const student1 = new Student("Mary", "Green");
const student2 = new Student("Lary", "Smith");

console.log(student1.display_full_name());

Output:

Mary Green

Note: Clearly, the ES6 way of defining classes is a much easier and compact way for creating classes in JavaScript. Hence, we use the class keyword anytime we create classes now.

JavaScript Encapsulation

Encapsulation puts the data variables and the data functions together inside a box. Encapsulation ensures that data can only be accessed using the data functions defined inside the class, and abstraction ensures not anyone outside this encapsulated box can access it.

But, we already saw that there is no actual concept of classes in JavaScript. So, JavaScript implements encapsulation using two ways: Function Scope and Closures.

Let's discuss both of them with examples.

Function Scope

When we define a variable or a function inside the function, we can only access it from inside and not from outside the function. This can be one way of implementing abstraction. Look at the example below.

function messageFunc(){
    const message= "Hey there!"
    console.log("Message from  inside: ",message);
}

// Calling the function which internally defines the message
messageFunc(); 

// Trying to access message from outside the function which defines it
console.log("Message from  outside: ",message);

The output for this code snippet says the right message when accessed from inside but throws an error when accessed from outside. Hence, the message is encapsulated.

Function Scope

Closures

We can create a function inside a function, and the inner function will be able to access the local variable defined inside the outer function. This is called closure.

Note: A closure is created every time a function is declared.

function messageFunc(){
    const message = "Hey there!"
    const displayMessage = function(){
        console.log(message);
    }
    displayMessage();
}

// Calling the function which internally defines the message
messageFunc();

// Trying to access message from outside the function which defines it
console.log("Message from outside: ",message);

Again, the output says that creating a closure helps encapsulate and restrict the data access only to inside the function.

Closures

JavaScript Inheritance

JavaScript lets objects inherit properties from parent objects or any other objects. It uses the concept of prototypal inheritance.

Prototype

JavaScript is a prototype-based language. The objects created here can inherit the properties and methods from other objects or their parent ones.

Let's create an object and console it.

Prototype

We only defined the property message to the messageObject, but we can see a lot of other methods. We didn't define them! These methods are inherited from the parent object, i.e., the prototype for the object data structure. When we create the object messageObject, we basically inherit all the properties object data structure has and add a new one, i.e. message.

Prototype with message object

What is Polymorphism?

Polymorphism is a concept used in the object-oriented paradigm that enables us to use the same function in different forms. This reduces repetition and makes the code snippet useful in many different cases. Polymorphism is implemented in JavaScript by generic, overloading, and structural sub-typing. Let us see them all in detail.

Generics (Parametric Polymorphism)

Parametric Polymorphism is implemented to make our code more generic. More precisely, it makes our code independent of defining data types. A more generic code doesn't care about the types while still maintaining types-safety.

Let us see an example:

Let's create a function to concat two data structures. Now, applying parametric Polymorphism, this code should run for two lists, two strings, or any two types. This is the idea behind this type of Polymorphism.

const concatData = (x,y) => {
    return y.concat(x);
}
console.log(concatData([1,2],[3,4]));
console.log(concatData("John","Smith"));

This code runs for both arrays and strings. Hence, Polymorphism is implemented.

Generics

Overloading (ad-hoc polymorphism)

Overloading in JavaScript is achieved using ad-hoc Polymorphism. Functions created using ad-hoc polymorphism exhibit different behaviors based on different types of input values. For example:

  • + when used on integers and floats, exhibit the property of addition.
  • + when used with strings and array does concatenation.
console.log(4 + 5)
console.log("My name is: "+"John Smith")

Output is:

9 & My name is John Smith.

Structural Subtyping (Structural Polymorphism)

Consider Person and Student.

const Person = {
    legs: 2,
    arms: 2,
}
const Student = {
    uniform: true,
}

Clearly, Student is a sub-type of Person, and Person is a super-type of Student. All the operations that can be performed on the Person can also be applied to the Student, but the reverse is not valid. Structural subtyping is about defining relationships. A sub-type will always have all the properties of another type, plus some additional features.

JavaScript and OOP

A fundamental feature of OOPS in javascript is its capability to model a problem using real-life objects. To achieve that, we should be able to define real objects and define relationships among them using three principles:

  • Association
  • Aggregation
  • Composition

Let's elaborate on these three principles:

JavaScript objects support Association, Aggregation and Composition

JavaScript objects support

Association

When two objects are unrelated and independent of each other, we define a relationship between them independent of any hierarchy. This means none of the objects is the child or parent of the other object, and the relation is called an association.

For example: In the case of a patient visiting a doctor, there is an independent relation. That doctor might be seeing multiple patients, and that patient can also be visiting multiple doctors simultaneously. None of them is a parent or a child. Hence, the relation is built through association.

Aggregation

There is an ownership in this type of relationship. It holds a parent/child relation. An essential property of this type of relationship is that the parent can live without the child object and vice versa. The child can also exist independently.

For example If an employee works for more than one department in a company, and anyone department gets deleted, the child, i.e., the employee, can still exist inside the company. Hence, this relationship exhibits aggregation.

Composition

Composition is a special type of aggregation. If the parent object dies, the child object also ceases to exist. To be more precise, the parent can exist without the child object, but vice versa is not true. The child cannot exist without its parent object.

How is JavaScript an OOP Language without Classes?

As already discussed, we do not create classes in JavaScript. Although we have the class keyword, it is just syntactic sugar over the prototype-based inheritance. Then how is OOPS in javascript implemented?

OOPS is not about creating classes! OOPS in javascript has its four main pillars explained above, and these four principle should be implemented using objects. In this prototype-based language, we use objects to implement encapsulation:

const student = {
    name: "Mary Green,"
    isStudying: () => console.log(`${student.name} is studying`)
}

Hence, we simply create JavaScript objects and achieve the object-oriented programming paradigm principles. We do not need classes for implementing OOPS.

Conclusion

  • JavaScript is a prototype-based language. It has support for both Object-oriented and functional programming paradigm. It is not a complete OOP or FP.
  • We cannot create classes in javascript. We have the class keyword, but it is just syntactic sugar for the prototype-based inheritance.
  • Oops in JavaScript is based on four main pillars:
    • Objects
    • Classes
    • Encapsulation
    • Inheritance
  • Classes are blueprints for real objects, and objects are the instances of the classes/prototypes.
  • Encapsulation is binding data and actions together, and inheritance says we can inherit some properties from the parent objects and define new properties and actions inside the child object.
  • Polymorphism is a concept used in the oops in javascript that enables us to use the same function in different forms.
Free Courses by top Scaler instructors