JS Prototypes

Prototype is a mechanism by which objects inherit behaviours from each other. A prototype is nothing but an object from which a particular object is inheriting. 

Whenever we create an object in JS, by default ‘__proto__’ property of newly created object points to Null Prototype object.

				
					let a = {}
a.__proto__.Test = "Test"  // Object 'a' has a default prototype object which is null prototype & to access null prototype object we use special property '__proto__'
console.log(a.__proto__)

// Output :
[Object: null prototype] { Test: 'Test' }
				
			

Function Prototypes

Whenever we create a function, a prototype object is created & we can access it using fun.__proto__ property and this object inherits from Null prototype object. 

				
					function abc(){

}
console.log(abc.__proto__)
console.log(abc.__proto__.__proto__)
console.log(abc.__proto__.__proto__.__proto__)

// Output :

				
			

Null Prototype

Whenever we access any of the property of any function or object, JS first tries to find that property in the scope of that object or function, if that property not present in that function or object then JS will move to its prototype and then try to find that property in that prototype. If that property is not there then JS will keep on moving to its prototype, if it is present there, it will return. 

In simple words, JS will keep on searching for a particular property in a prototype chain. 

				
					
/*
Null Prototype Object
*/

const a = {}
function b(){
}
const c = {}
a.__proto__.Prop1 = "Test Prop1"
console.log(a.Prop1)
console.log(b.Prop1)
console.log(c.Prop1)



				
			

Prototype of objects created by constructor

As soon as we create a constructor or as soon as we invoke a function using ‘new’ keyword, JS creates a new object & that object can be reused using a property called prototype so we can use con.prototype and this object acts as a prototype for all the objects that we create by using the same constructor. 

				
					/*
All objects created by a constructor share same prototype
*/

function Phone(make){
    this.make = make
}

let iPhone = new Phone("Apple")
let nexus = new Phone("Google")

if(Phone.prototype === Phone.__proto__){
    console.log("Same")
}else{
    console.log("Not same")
}

// Output :
Not same
				
			

Constructor Prototype usage

Common behaviour can be added to the prototype instead of adding it inside the constructor function, so immediate benefit is the behaviour is not getting copy over to all the new objects that are getting created. 

				
					/*
All objects created by a constructor share same prototype
*/

function Phone(make){
    this.make = make
}

Phone.prototype.getMake = function(){
    return this.make
}

Phone.prototype.switchOn = function(){
    console.log("Device switched on")
}


let iPhone = new Phone("Apple")
let nexus = new Phone("Google")

console.log(iPhone)
console.log(iPhone.getMake())
nexus.switchOn()

// Output :
Phone { make: 'Apple' }
Apple
Device switched on
				
			

Prototype Inheritance

In prototypal inheritance, we need to change the __proto__ property inside the object to whatever object we want it to point to and that object becomes the parent of this object.

				
					/*
Changing default prototype object
*/

const animal = {
    name: "Animal",
    jump: function(){
        console.log(`${this.name} jumps`)
    },
    play: function(){
        console.log(`${this.name} plays`)
    }
}

const dog = {
    name: "Jax",
    __proto__:animal
}

const cat = {
    name: "Bella",
    __proto__: animal
}

dog.jump()
cat.play()

// Output :
Jax jumps
Bella plays