# All about JavaScript Prototypes

The `class` keyword in JavaScript is syntactic sugar. Internally it uses prototypal inheritance. Prototypal inheritance is like Java or Python classical inheritance. It allows an object to access another object's methods and properties.

It helps

* Implement inheritance
    
* Avoid repeating functionalities
    
* Making innovative programming paradigms
    

Both `array` and `function` are objects in JavaScript. So any `object`, `array`, and `function` can use the property of the parent prototyped chain `object` properties and methods.

**Quick Example**

Let's run the following code,

```js
const parent = {
    foo: () => {
        console.log('I am parent!');
    },
    bar: 'Hello World!'
};

const child = {
    foo: () => {
        console.log('I am child!');
    }
}

child.__proto__ = parent;

child.foo();
console.log(child.bar);
```

We will see the output,

```plaintext
I am child!
Hello World!
```

Here, even if the `child` object does not have the `bar` property, it will inherit the property from the parent object using the prototype chain.

# Overview of Prototypes

## **Example 1: Object Prototypes Chain**

Let's declare an object

```js
const obj = {};
```

We will find the `base object` if we check the prototype chain.

```js
obj.__proto__
```

---

## **Example 2: Array Prototypes Chain**

```js
const array = [];
```

Here we created an array. This array object is created by the constructor of an object. We can access these constructors and other array methods like `concat`, `fill`, `find`, `push`, `pop` etc using the following,

```js
array.__proto__;
```

Using the `prototypes chain` we can access the base object, using the following,

```js
array.__proto__.__proto__;
```

From this base object, we can access the `base object` properties and methods like, `constructor`, `hasOwnProperty`, `toString`, `valueOf` etc.

Now we can use the base object method using the prototypes chain. For example, to use the `toString` method from the base object, we can write

```js
array.toString();
```

Since our array is empty, it will return an empty string.

---

## **Example 3: Function Prototypes Chain**

Let's create a method

```js
function a() {}
```

Using the prototypes chain, we can observe the `native function`. The `native function` is the one, that created all other `functions`.

```js
a.__proto__;
```

Using the `prototypes chain`, if we go one step closer, we will find the `base object`.

```js
a.__proto__.__proto__;
```

# Creating our Prototypes

The simplest way to create a prototype is by using the `__proto__`,

```javascript
const parent = {
    foo: () => {
        console.log('I am parent!');
    },
    bar: 'Hello World!'
};

const child = {
    foo: () => {
        console.log('I am child!');
    }
}

child.__proto__ = parent;

child.foo();
console.log(child.bar);
```

But while creating our prototypes, we should be aware of the,

* We should never use the keyword `__proto__` because that impacts execution performance.
    
* The keyword is named intentionally with four underscores, so no one accidentally uses it.
    

To create the `prototypes-chain` we can use the `Object.create()` function.

```js
const human = {
  mortal: true
};
const socrates = Object.create(human);
socrates.age = 80;
console.log(`Age of socrates: ${socrates.age}`);
console.log(
  `Is human a prototypes of socrates: ${human.isPrototypeOf(socrates)}`
);
```

This will give us the following output,

```bash
Age of socrates: 80
Is human a prototypes of socrates: true
```

# Prototypes In Action

Moment of truth. We will see how we can get benefits from the prototypes.

Let's create two characters,

```js
const dragon = {
  name: 'Tanya',
  fire: true,
  fight() {
    return 5;
  },
  sing() {
    return `I am ${this.name}, the breather of fire`;
  }
};

const lizard = {
  name: 'Kiki',
  fight() {
    return 1;
  }
};
```

Now we want to use the `sing()` method of for `lizard`. But `lizard` does not have the `sing()` method. In this case, we have to use the `dragon` object `sing()` method.

To use the `dragon` objects method, we can use the `bind` property.

```js
const singLizard = dragon.sing.bind(lizard);
singLizard();
```

This will give the output

```bash
I am Kiki, the breather of fire
```

Now if we update the `dragon` objects `sing()` method, that, to sing, the `fire` property is will be required, then the new `dragon` object will be,

```js
const dragon = {
  name: 'Tanya',
  fire: true,
  fight() {
    return 5;
  },
  sing() {
    if (this.fire) {
      return `I am ${this.name}, the breather of fire`;
    }
  }
};
```

In this case, if we call `singLizard()` the sing method will not return the statement.

To return the statement, we have to bind the `fire` property for the `lizard` also from the `dragon` object.

To resolve this issue, instead of binding, we can use the `prototypes chain`.

```js
lizard.__proto__ = dragon;
lizard.sing();
```

In this case, when the `sing()` method will not be found in the `lizard` object, it will check the prototypes chain and execute the `sing()` method from there.

After using the `prototypes chain`, if we invoke the `fight()` method for the `lizard` object,

```js
lizard.__proto__ = dragon;
lizard.fight();
```

This will return

```bash
1
```

Because this `fight` method already exists in the `lizard` object. So it will not go to the `prototypes-chain` for `fight()` method of `dragon` object.

We can if the `dragon` is a prototypes of `lizard` by the following,

```js
dragon.isPrototypeOf(lizard);
```

This will be `true`. And this `isPrototypeOf` came from the `base object`, also using the `prototype chain`.

# Properties of Prototypes

## Property 1: Prototype does not copy properties, it is inherited

We will see for `object`, `array` and `function` examples that all the prototypes chain just inherited the property from the prototyped object.

**Prototypes Chain With Object**

Using the previous example,

```js
const dragon = {
  name: 'Tanya',
  fire: true,
  fight() {
    return 5;
  },
  sing() {
    return `I am ${this.name}, the breather of fire`;
  }
};

const lizard = {
  name: 'Kiki',
  fight() {
    return 1;
  }
};

lizard.__proto__ = dragon;

for (let prop in lizard) {
  console.log(
    `Is ${prop} lizards own property: ${lizard.hasOwnProperty(prop)}`
  );
}
```

This will give us output

```bash
Is name lizards own property: true
Is fight lizards own property: true
Is fire lizards own property: false
Is sing lizards own property: false
```

So we can see, only `name` and `fight` are the `lizard` own property. Both `fire` and `sing` properties have come from the `prototypes-chain`.

Since it is not copying the properties, this is helpful. For example, if we use `sing` method of `dragon` object in multiple places, we can use one single instance. We are not repeating ourselves and saving memory.

**Prototypes Chain With Array**

let's define an array.

```js
const myArr = [];
```

We know the JavaScript array has a property called `map`. Let's check

```js
myArr.hasOwnProperty('map');
```

This will return `false`. Because the `map` come through the `prototypes-chain`. When we create an array, it is created by the `Array` object. Using `prototypes` chain we can access the `Array` and check the `map` property existence.

```js
myArr.__proto__.hasOwnProperty('map');
```

This should return `true`.

**Prototypes Chain With Function**

Let's create a `function`

```js
function myMethod() {}
```

We know `function` are a special type of `object` in `Javascript`.

So the following statement should return `true`.

```js
myMethod.hasOwnProperty('call');
```

But this will return `false`.

Because, these `call`, `bind`, `apply` methods appear in a method through the `prototypes-chain`.

The `__proto__` of the `myMethod` linked to the native base function `prototypes` object.

That base function `prototypes` object contains all the following,

* `call`
    
* `apply`
    
* `bind`
    
* `__proto__`, this point to the base object of Javascript
    
* Many more ...
    

```js
myMethod.___proto__.hasOwnProperty('call');
```

This will return true.

And this `__proto__` of the base function `prototypes` chain to the base object `prototype` property.

Base object `__proto__` of the `prototypes` property point to the `null`.

---

## Property 2: Only the function and base object have the `prototype` object

Let's create an object and a function and check if there is `prototype` object.

```js
const obj = {};
function myFunc() {}

console.log(obj.hasOwnProperty('prototype'));
console.log(myFunc.hasOwnProperty('prototype'));
```

This will return

```bash
false
true
```

Now we know the base object of JavaScript `Object` has a property `property`.

```js
Object.hasOwnProperty('prototype');
```

This will return `true`.

Actually, the `Object` of the JavaScript is a function, not an object.

# Usage of Prototypes in Daily Programming

To me, this is the most interesting section. We will go through some real-world scenarios where we can implement the concept of prototypes.

**Add a new functionality in** `Date` object

Let's add a new function named `lastYear` of the `Date` object, that will return the 1 year earlier than the current year.

```js
Date.prototype.lastYear = function () {
  return this.getFullYear() - 1;
};
new Date('1900-10-10').lastYear();
```

Here we use the `function` keyword instead of the `arrow` method to use `dynamic-scope` instead of `lexical-scope`.

When using the `function` keyword, the `this` context is the `new Date`.

But with the `arrow method` the `this` context is the `arrow method` itself, given below,

```js
Date.prototype.lastYear = () => {
  return this.getFullYear() - 1;
};

new Date('1900-10-10').lastYear();
```

It will throw an error of,

```plaintext
TypeError: this.getFullYear is not a function
```

---

**Manipulate the** `map` functionality of the array

We will add the text `manipulated` before each value of the array,

```js
Array.prototype.map = function (args) {
  const newArray = [];
  this.forEach(val => newArray.push(`manipulated ${val}`));
  return newArray;
};

console.log([1, 2, 3].map());
```

This will give us output

```bash
[ 'manipulated 1', 'manipulated 2', 'manipulated 3' ]
```

## Final Thoughts

Prototypes are one of the core foundations of JavaScript. Let me know for any queries. Also, you can share your thoughts on how you utilize the prototypes in daily programming.

References: [JavaScript: The Advanced Concepts](https://www.udemy.com/course/advanced-javascript-concepts/) by [Andrei Neagoie](https://www.udemy.com/user/andrei-neagoie/).
