Prototypes in JavaScript

Prototypes in JavaScript

Constructors, Prototype and Prototypical Inheritance

·

6 min read

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

image.png

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,

image.png

Car.prototype = Object.create(Vehicle.prototype);

Warning this doesn't work

Car.prototype = Vehicle.prototype;

image.png

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

Thank you!!

Did you find this article valuable?

Support DevWithAvatar by becoming a sponsor. Any amount is appreciated!