JavaScript
OOP in JavaScript

OOP in JavaScript

Before we start diving right into the fun of classes, let’s briefly say something about object-oriented programming (OOP). OOP is a very important programming  paradigm wherein code is structured in objects, leading to more maintainable and reusable code. Working with OOP teaches you to really try to think of all sorts of  topics in objects, by bundling properties in such a way that they can be wrapped  in a blueprint called a class. This in turn might be inheriting properties from a parent class.

Classes in JavaScript encapsulate data and functions that are part of that class. If you create a class, you can later create objects using that class using the following syntax:

class ClassName {
 constructor(prop1,prop2) {
   this.prop1 = prop1;
   this.prop2 = prop2;
 }
}
let obj = new ClassName("arg1","arg2")

This code defines a class with ClassName as name, declares an obj variable, and initializes this with a new instance of the object. Two arguments are provided. These arguments will be used by the constructor to initialize the properties.

Defining a class Fruit

class Fruit {
  constructor(name,color){
    this.name = name;
    this.color = color;
  }  
}

Declaring an object variable of Class Fruit

let fruit = new Fruit("Banana",'Red');

Printing the properties of This Fruit object

console.log('Color of ',fruit.name," is",fruit.color);

Output

Color of  Banana  is Red

Constructors

The constructor method is a special method that we use to initialize objects with our class blueprint. There can only be one constructor in a class. This constructor contains properties that will be set when initiating the class.

Here is an example of a constructor in a Person class.

class Fruit{
    constructor(name,color,price){
        this.name = name;
        this.color = color;
        this.price = price;
    }
}
let f1 = new Fruit('Banana','Red',23.6)

Here the new word is what tells JavaScript to look for the special constructor function in the Fruit class and create a new object. The constructor gets called and returns an instance of the Fruit object with the specified properties. This object gets stored in the f1 variable.

If we use our new f1 variable in a logging statement, we can see that the properties are really set:

console.log(f1.color,f1.name," costs $ ",f1.price)

Output

Red Banana costs $ 23.6

Methods

In a class, we can specify functions. This means that our object can start doing things using the object’s own properties – for example, printing a name.

Functions on a class are called methods.

When defining these methods, we don’t use the function keyword. We start directly with the name:

class Fruit{
    constructor(name,color,price){
        this.name = name;
        this.color = color;
        this.price = price;
    }
    greet(){
        console.log("Hi I am ",this.color,this.banana)
    }
}

We can call the greet method on a Fruit object like this:

let f1 = new Fruit('Cherry','Purple',6)
//calling greet method
f1.greet()

Output

Hi I am Purple Cherry

Just like functions, methods can also take parameters and return results:

class Fruit{
    constructor(name,color,price){
        this.name = name;
        this.color = color;
        this.price = price;
    }
    greet(){
        console.log("Hi I am ",this.color,this.name)
    }
    calculation (amount){
        this.total = this.price * amount;
        console.log("Total cost: ",this.total);
    }
}

Calling the calculation method

let f1 = new Fruit('Cherry','Purple',6)
//Calling calculation method
total = f1.calculation(5);

Output

Total cost: 30

Inheritance

Inheritance is one of the key concepts of OOP. It is the concept that classes can have child classes that inherit the properties and methods from the parent class. For example, if you needed all sorts of Phone objects in your application, you could specify a class named Phone in which you specify some shared properties and methods of various Phones. You would then go ahead and create the specific child classes based on this Phones class, for example, android, i-phone, dumb-phone, and desk-phone.

class Phone{
    constructor(name,price){
        this.name = name;
        this.price = price;
    }
    Model(model){
        console.log("Model no. of ",this.name," is ",model);
    }
    
}

Here we have a method in our Phone class:  Model.

In the following code the Soon class inherit properties and methods from the Phone class and adds a property and method of its own.

class Soon extends Phone {
  
  constructor(name,price,GPU) {
    super(name,price);
    this.GPU = GPU;
  }
  
  GPU_cores(number){
    console.log(this.GPU," of Soon has: ",number," cores");
  }
}

With extends keyword we specify that a certain class is a child of another class. In this case Soon is child class of Phone. Assuming that Soon produces phones with GPU, we have added a property named GPU and a method displaying number of cores in that GPU.

The super word in the constructor is calling the constructor from the parent, the Phone constructor in this case. This makes sure that the fields from the parent are set as well and that the methods are available without having to do anything else: they are automatically inherited. Calling super() is not optional, you must do it when you are in a class that is inheriting from another class, else you will get a RefereceError.

Because we have access to the fields of Phone in Soon, this will work.

let S1 = new Soon("SOON4",36,"Ahora");
S1.greet("SOON416");
S1.GPU_cores(2000);

Output

Model no. of SOON4 is SOON416
Ahora of Soon has: 2000 cores

Prototype in JavaScript

JavaScript is a dynamic language. You can attach new properties to an object at any time as shown below.

function Student() {
    this.name = 'Vedhika';
    this.gender = 'Female';
}

var studObj1 = new Student();
studObj1.age = 5;
alert(studObj1.age); // 15

var studObj2 = new Student();
alert(studObj2.age); // undefined

Output

5
undefined

As you can see in the above example, age property is attached to studObj1 instance. However, studObj2 instance will not have age property because it is defined only on studObj1 instance.

So what to do if we want to add new properties at later stage to a function which will be shared across all the instances?

The answer is Prototype

The prototype is an object that is associated with every functions and objects by default in JavaScript, where function’s prototype property is accessible and modifiable and object’s prototype property (aka attribute) is not visible.

Every function includes prototype object by default.

The prototype object is special type of enumerable object to which additional properties can be attached to it which will be shared across all the instances of it’s constructor function.

So, use prototype property of a function in the above example in order to have age properties across all the objects as shown below.

function Student() {
    this.name = 'Ritviz';
    this.gender = 'M';
}

Student.prototype.age = 5;

var studObj1 = new Student();
alert(studObj1.age); 

var studObj2 = new Student();
alert(studObj2.age); 

Output

5
5

Prototype in JavaScript Objects

A prototype is the mechanism in JavaScript that makes it possible to have objects. When nothing is specified when creating a class, the objects inherit from the Object.prototype project.

There is a prototype property available on all classes, and it is always named “prototype”. We can access it like this:

ClassName.prototype

Let’s give an example of how to add a function to a class using the prototype property. In order to do so, we will be using this Fruit class:

class Fruit{
    constructor(name,color,price){
        this.name = name;
        this.color = color;
        this.price = price;
    }
}

And here is how to add a function to this class using prototype:

Fruit.prototype.total = function(number) {
    total = number * this.price;
    console.log("Total cost is: ",total);
};

prototype is a property holding all the properties and methods of an objects. So,adding a function to prototype is adding a function to the class. You can use prototype to add properties or methods to an object, like we did in the above example in our code with the introduce function. You can also do this for properties:

Fruit.prototype.vitamin = true;

And then you can call them from instances of Fruit:

let f1 = new Fruit('banana','red',56);
f1.total(5)
console.log(f1.name,"have vitamin? ",f1.vitamin);

Output

Total cost is: 280
banana have vitamin? true

So the methods and properties defined via prototype are really as if they were defined in the class. This means that overwriting them for a certain instance does not overwrite them for all instances.

For example, if we were to have a second Fruit object, this fruit could overwrite the vitamin value and this would not change the value for our object with the name as Banana.

let f1 = new Fruit('banana','red',56);
f1.total(5)
console.log(f1.name,"have vitamin? ",f1.vitamin);

let f2 = new Fruit('Cherry','Blue',520);
f2.vitamin = false;
console.log(f2.name,"have vitamin? ",f2.vitamin);

let f3 = new Fruit('Mulberry','Brown',20);
console.log(f3.name,"have vitamin? ",f3.vitamin);

Output

Total cost is: 280
banana have vitamin? true
Cherry have vitamin? false
Mulberry have vitamin? true