OOP in JavaScript. #1. Constructor and Prototypes
Tags: javascript, oop
Published: 2021-02-15 18:33:16

### Introduction
Hi! Today I will start a series, in which I will talk about OOP in Javascript. I will start by explaining constructor functions and prototypes.

### OOP in JavaScript

OOP is a programming paradigm (style of code) based on the concept of objects.

OOP in JS is different from the classical OOP. 
- In classical OOP we have objects that are instantiated from classes.
- In JS OOP, we create objects, then we link them to a prototype object (that got all the methods), then the objects inherit all the methods of the prototype (It can be also said that: the prototype **delegates** the methods to the objects).

#### How can we create objects, their Prototype, and Linking Them Together?

We have three ways in JS to achieve that:
**1- Constructor Functions.**
**2- ES6 Classes.**
**3- Object.create ().**

Today we will discuss the first one, which is: **Constructor Functions**.

### Constructor Functions

When we create a constructor function, the convention is to start its name with a capital letter.

Arrow function won't work as a constructor function, because it doesn't have its own *this* keyword.

This constructor function can be used to make any number of objects as we want.


#### The Difference Between Calling a Constructor Function and Calling a Normal Function:

When we call a constructor function, we use the **new** keyword.

Example:

```js
const Person = function (firstName, birthYear) {
    this.firstName = firstName;
    this.birthYear = birthYear;
}

// Making an instance of the constructor function
const Abdelrahman = new Person ('Abdelrahman', 2001);
const Abdelrahman = new Person ('Habiba', 2003);
```


#### When we invoke a constructor function, the following do happen:

- An empty object is created (empty object means that it has neither properties nor methods).

> We can add some properties for that empty object in the constructor function’s body using the *this* keyword (just like we did in the previous example).

- The *this* keyword is set to point to the newly created empty object.

- The newly created object is linked to a prototype, which means:

&nbsp;&nbsp;&nbsp;&nbsp;A- Creating a new **\_\_proto__** property for the object.

&nbsp;&nbsp;&nbsp;&nbsp;B- Set it to the **prototype** property of the constructor function.

- This empty object is returned from the constructor function.

If that seems overwhelming to you, don't worry! Just stick with me, and you will understand everything when I start talking about prototypes.


### The need for Prototypes

Suppose that we want to add some methods to the object.

It’s a bad practice to add them inside the constructor function body, as those methods will be shared with all instances, while we don’t always need the methods to be shared. That will affect performance!

Example: 

```js
const Person = function (firstName, birthYear) {
    this.firstName = firstName;
    this.birthYear = birthYear;
    
    // Bad Practice (methods inside constructor function)
    this.calcAge = function () {
        console.log(2037 - this.birthYear);
    }
}
```

The solution to the previous problem is using prototypes.

### Prototypes

Each and every function (including the constructor function) in JS has a property called: **prototype**.

When we add methods (or properties) to the prototype property of our constructor function, only one copy of this method is made, to be used later by all of the instances.

All the objects (instances) will inherit all the methods defined in the prototype property. This is called **prototypal inheritance**.

When we call a property or a method on an object, if it’s not found in the object itself, JS will search on its prototype.

The following example shows, how can we add a method to the prototype property of the function constructor:

```js
Person.prototype.calcAge = function () {
    console.log(2037 - this.birthYear);
}

Abdelrahman.calcAge ();
```
Any object always has access to the methods and properties from its prototype. To do that, we use the special property **\_\_proto__** that is available for all JS objects.

> Remember: **\_\_proto__** used to access the prototype for any object. The **prototype** property is for the constructor function.

Constructor function’s **prototype** property is not used to yield the prototype for the constructor function itself, but to yield the prototype for all the objects created from this constructor.

> Note: **prototype** is a property, but **constructorFunction.prototype** is an object.

Example to illustrate the previous statements:

```js
console.log(Abdelrahman.__proto__ === Person.prototype);  // true
console.log(Person.prototype.isPrototypeOf (Abdelrahman)); // true
console.log(Person.prototype.isPrototypeOf (Person));   // false
```

> Note: We used the **isPrototypeOf** method (for the prototype property) to check whether the constructor function’s prototype is the prototype of the object passed or not.

### Adding properties to the Prototype of the Constructor function

This is not practical in many cases, as all of the instances will share the same value for this property.

```js
Person.prototype.species = "Homo Species";
console.log(Abdelrahman.species, habiba.species);  // Homo Species Homo Species
```

We can use the **hasOwnProerty** method for any object and pass an object property (as a string) to it. It will return true if the passed property is not a prototypal property.

```js
console.log(Abdelrahman.hasOwnProperty ('species'));   // false
```

### Prototype Chain

It's a series of links between objects linked using prototypes.

Each created object in JS is just an instance of the **Object** constructor function.

When we use the curlies {} to write an object literal, it’s equivalent to writing **new Object** constructor.

The prototype of any object is the constructor function that this object was created from. When we reach **Object**, it’s on the top of the prototype chain, and it has no parent, so its prototype will be **null**.

```js
console.log(Abdelrahman.__proto__.__proto__);  // Object.prototype
console.log(Abdelrahman.__proto__.__proto__.__proto__);    // null
```

### Applying what we learned

We can apply what we learned in the Array constructor.

Creating an array using the brackets [], is equivalent to creating it using the new Array constructor.

```js
const arr = [1, 3, 1, 3, 6, 6, 5, 6, 1];
console.log(arr.__proto__ === Array.prototype); // true
```

We can add a method to the Array constructor function prototype (and all array objects will inherit it).

```js
const arr = [1, 3, 1, 3, 6, 6, 5, 6, 1];
Array.prototype.unique = function () {
    return [...new Set (this)];
};
console.log(arr.unique ()); // Array(4) [ 1, 3, 6, 5 ]
```

That's it for today! I hope you learned from it. See you soon!