Prototypes in JavaScript.
Tags: javascript, beginners, webdev, codenewbie
Published: 2023-10-25 06:15:57

The prototype chain is a fundamental concept in JavaScript's object-oriented programming model. It plays a crucial role in how objects inherit properties and methods from other objects, allowing for code reuse and the creation of object hierarchies.

to understand the prototype let us explore with a basic example
```js
const car = function(make, model){
  this.make = make
  this.model = model
  console.log(`My car is ${make} ${model}`)
}

const c1 = new car('Tesla', 'Roadster') // My car is Tesla Roadster
console.log(c1) //{make: "Tesla", model: "Roadster"}
car.prototype.speed = function (){
  return `My car is ${this.make} ${this.model} and it has a speed of 120km/h`
}
console.log(c1.speed()) //My car is Tesla Roadster and it has a speed of 120km/h)
console.log(car.prototype) // it has a prototype speed function now
console.log(c1.__proto__) // car {speed:f} same as above
console.log(c1.__proto__.__proto__) // Object {} with the key values of all properties
console.log(c1.__proto__.__proto__.__proto__) // null
console.log(car.prototype.__proto__) // Object {}
console.log(car.prototype.__proto__.__proto__) // {} null

console.log(car.prototype === c1.__proto__) // 'true' this means the car prototype is the prototype of its instance c1
console.log(car.prototype.isPrototypeOf(c1))//'true' it is same as writing above code

//Manually setting the properties
car.prototype.drive = 'Front Wheel'

console.log(c1.drive) // Front Wheel
console.log(c1.hasOwnProperty('drive'))//false
console.log(c1.hasOwnProperty('make'))//true
```



- **Prototypes and Objects:** In JavaScript, almost everything is an object, and each object has a prototype, which is another object. Objects inherit properties (including methods) from their prototypes. You can think of the prototype as a template or a "parent" object.
    
- **Object Creation:** When you create a new object, either with object literals (`{}`), constructors, or classes, it is initially empty, but it has a hidden reference to its prototype. This prototype reference is accessible via the `__proto__` property (though it's typically accessed using the `Object.getPrototypeOf()` method).
```js
const myObject = {}; // An empty object
console.log(Object.getPrototypeOf(myObject)); // The prototype of myObject

```
- **Property Lookup:** When you try to access a property or method on an object, JavaScript first looks for that property or method on the object itself. If it doesn't find it, it continues searching in the object's prototype (the prototype of the object). This process continues recursively until the property or method is found or until the prototype chain ends at the `Object.prototype`, which is the ultimate prototype for most objects in JavaScript.
```js
const person = {
  firstName: 'John',
  lastName: 'Doe',
};

console.log(person.firstName); // Accesses firstName on the person object
console.log(person.toString()); // Searches for toString in the prototype chain (found in Object.prototype)
```
- **Prototype Inheritance:** Objects inherit properties and methods from their prototypes. This inheritance allows you to define shared behaviors and properties in prototype objects and reuse them across multiple objects.
```js
function Person(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
}

Person.prototype.getFullName = function () {
  return this.firstName + ' ' + this.lastName;
};

const john = new Person('John', 'Doe');
console.log(john.getFullName()); // Inherited method

```
In this example, `john` is an instance of the `Person` constructor, and it inherits the `getFullName` method from `Person.prototype`.


## Prototype Chaining

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

Person.prototype.calcAge = function(){
  console.log(`${this.name} age is ${2023 - this.birthYear}`)
}

const Jonas = new Person('Jonas',1990)
console.log(Jonas.__proto__) // logs Person.prototype
console.log(Person.prototype.__proto__)// returns Object.prototype
console.log(Person.prototype.__proto__.__proto__)// returns null
console.log(Jonas.hasOwnProperty('name'))//true--- this method is inherited from Object prototype
```

consider above program. here what is happening is. 

Jonas is an Object with the `__proto__` property which is equal to `Person.prototype`
and this person prototype is itself an object which is created from the constructor function `Person()`
Since, every object has its own `__proto__` property then this means that person prototype should also has its own i,e, `Person.prototype.__proto__` this property is equal to the `Object.prototype`
Now looking at this Object prototype, it is actually created from yet another constructor function `Object()` so basically every object behind the scene is created from `Object()` constructor function and therefore inherits Object prototype (`{}=== new Object()`)

![Prototype Chaining](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n2y15n9e4oxtwylbh4mq.png)

'The source of this image detail is from the Udemy [course](https://www.udemy.com/course/the-complete-javascript-course/)

In the statement `console.log(Jonas.hasOwnProperty('name'))` What is happening that `hasOwnProperty` is not in the Object Jonas so JS lookup in its prototype which is `Person.prototype`, Since it is also not defined in there, it will lookup in the `Person.prototype.__proto__` and then it reaches the `Object.prototype` which actually contains this function `hasOwnProperty`

## Prototype Inheritance on Built-In Objects

let us try this on Arrays
```js
const array = [1, 2, 3, 4, 5, 4, 5, 8, 9, 9];
console.log(array.__proto__) // Array Object prototype, 
console.log(array.__proto__.__proto__) // Object prototype 
console.dir(array) // this can give the complete prototype chain in console

Array.prototype.unique = function(){
  return [...new Set(this)];
}

console.log(array.unique()) //[1, 2, 3, 4, 5, 8, 9]
```

Here we have tried prototype chain on the array method, once in console we can see all the array methods as its prototype
so` filter` is actually the prototype of the Array object, thats why at mdn document it is written as `Array.prototype.filter`