Before we start with Prototypes, we need to understand Object Constructors.
Let's take an example,
We are playing a game and we need to store name and age of players, So, how to do that
- First way is to create separate name and age variables for each player like this,
var playerOneName = "Rohit";
var playerOneAge = 25;
var playerTwoName = "Virat";
var playerTwoAge = 33;
console.log(playerOneName, playerOneAge);
console.log(playerTwoName, playerTwoAge);
/* output will be:-
Rohit 25
Virat 33 */
This method will be too lengthy if there are large no. of players
- well we have another method, we can create an object for each player which will contain player's name and age.
var playerOne = {
name: "Rohit",
age: 25
}
var playerTwo = {
name: "Virat",
age: 33
}
console.log(playerOne);
console.log(playerTwo);
// output will be: -
// { name: 'Rohit', age: 25 }
// { name: 'Virat', age: 33 }
But this method also is to large when it comes to large no of player.
Now, here comes the Object Constructors
Object Constructors are special functions that are used to initialize an object. The new keyword is used for object initialization along with object constructors
// object constructor
function Player(name, age) {
this.name = name;
this.age = age;
}
var player1 = new Player("Rohit", 25);
var player2 = new Player("Virat", 33);
console.log(player1);
console.log(player2);
// output will be: -
// Player { name: 'Rohit', age: 25 }
// Player { name: 'Virat', age: 33 }
This method is simple, easy and short as compared to other methods. If we want a change that should reflect in all instances of Player then we just need to add it into Player constructor
Now let's see what is Prototype ?
It is the parent object from where the current object inherits all his property and ".prototype" attribute is the reference to the parent object.
let's continue with Player() example,
Player.prototype.info = function () {
console.log(`Hello, I am ${this.name} and I am ${this.age} year old.`);
}
player1.info();
player2.info();
// output will be: -
// Hello, I am Rohit and I am 25 year old.
// Hello, I am Virat and I am 33 year ol
Let's try see what prototype of Player is containing,
console.log(Player.prototype);
// output will be: -
// { info: [Function (anonymous)] }
you must be wondering why name and age are not there in prototype, Because name and are not stored in prototype.
Now, let's try to see to see what's inside of Player1's constructor,
console.log(player1.constructor.toString());
// output will be: -
// function Player(name, age) {
// this.name = name;
// this.age = age;
// }
Read this to understand more,
If you’re using constructors to make your objects it is best to define functions on the prototype of that object. Doing so means that a single instance of each function will be shared between all of the Student objects. If we declare the function directly in the constructor, like we did when they were first introduced, that function would be duplicated every time a new Player is created.
Prototypical inheritance
JavaScript does not have Classical Inheritance based on classes, therefore all inheritance in JavaScript is made possible through the prototype prototype.
- JavaScript has a prototype-based inheritance mechanism.
By the way what is Inheritance ?
Inheritance is a programming paradigm where objects (or Classes in some languages) can inherit properties and methods from other objects (or Classes). In JavaScript, you implement inheritance with the prototype property.Inheritance is a programming paradigm where objects (or Classes in some languages) can inherit properties and methods from other objects (or Classes). In JavaScript, you implement inheritance with the prototype property.
For example All vehicles have some common properties, all cars are vehicles and all cars we see on streets are instance of car class.
Let me elaborate more on this example,
// For giving example I have set Random values
function Vehicle() {
this.engine = '120cc';
this.noOfWheels = 4;
this.noOfGears = 5;
}
// adding getinfo() in vehicle prototype
Vehicle.prototype.getinfo = function () {
console.log(`Engine:- ${this.engine}, Wheels:- ${this.noOfWheels}`);
}
// Car constructor
function Car(name, color, id) {
this.name = name;
this.color = color;
this.id = id;
}
// adding Vehicle's properties tp Car's prototype
Car.prototype = new Vehicle();
var Audi = new Car("Audi", "Red", 4652);
Audi.getinfo();
console.log(Audi.name, Audi.color);
// output will be: -
// Engine:- 120cc, Wheels:- 4
// Audi Red
Here object Audi inherited all its properties form object Car and object Car inherited some it's properties from object Vehicle.
- here we can see Audi object has getinfo() function which belongs to Vehicle and name attribute from Car Object
Now let's try to print ".toString()" function with Audi,
console.log(Audi.toString());
// output will be: -
// [object Object]
You must be wondering why above code doesn't show error because we have not defined toString() function in any Object,
Here comes a Twist,
- if you want to access a property of an object, the search for the property begins directly on the object. If the JS runtime can’t find the property there, it then looks for the property on the object’s prototype—the object it inherited its properties from.
- If the property is not found on the object’s prototype, the search for the property then moves to prototype of the object’s prototype (the father of the object’s father—the grandfather). And this continues until there is no more prototype (no more great-grand father; no more lineage to follow).
- This in essence is the prototype chain: the chain from an object’s prototype to its prototype’s prototype and onwards. And JavaScript uses this prototype chain to look for properties and methods of an object.
- If the property does not exist on any of the object’s prototype in its prototype chain, then the property does not exist and undefined is returned.
This diagram will help you to understand better,
Recommended Method for Prototypal Inheritance
Car.prototype = Object.create(Vehicle.prototype);
Warning this doesn't work
Car.prototype = Vehicle.prototype;
Let's see what happens when we use above method for inheritance,
Car.prototype = Vehicle.prototype;
var vehicleobj = new Vehicle();
var carobj = new Car();
Car.prototype.getSpeed = function () {
console.log("This car is too fast.")
}
carobj.getSpeed();
vehicleobj.getSpeed();
// output will be: -
// This car is too fast.
// This car is too fast.
console.log(Vehicle.prototype);
console.log(Car.prototype);
// output will be: -
// { getinfo: [Function (anonymous)], getSpeed: [Function (anonymous)] }
// { getinfo: [Function (anonymous)], getSpeed: [Function (anonymous)] }
Here Car's and Vehicle's prototype is same, thus getSpeed() is associated with both of them.
Car.prototype = Object.create(Vehicle.prototype);
var vehicleobj = new Vehicle();
var carobj = new Car();
Car.prototype.getSpeed = function () {
console.log("This car is too fast.")
}
carobj.getSpeed();
vehicleobj.getSpeed();
// output will be: -
// This car is too fast.
// error
console.log(Vehicle.prototype);
console.log(Car.prototype);
// output will be: -
// { getinfo: [Function (anonymous)] }
// Vehicle { getSpeed: [Function (anonymous)] }
So be alert while doing Prototypical Inheritance.
Hope you like this blog, please do give feedback