Hello Sunil
javascript-prototype-feature-image

JavaScript Prototype – Simple Explanation

Understanding prototypal inheritance is the key to understanding how objects inherit properties in JavaScript. This concept is also asked often during JavaScript interviews.

In this post, we will help you understand prototypal inheritance.

JavaScript’s Prototypal Inheritance Explained Using CSS

Prototypal inheritance is arguably the least understood aspect of JavaScript. Well the good news is that if you understand how CSS works, you can also understand how JavaScript prototypes work.

The JavaScript uses the Prototypes to implement the inheritance. Inheritance makes code reusable, readable & maintainable by sharing the instance of existing properties & methods across objects

It’s beautiful when something simple is able to explain something seemingly complex so here we go.

Prototypes in CSS Buttons

styled-css-two-buttons

See the two buttons above? We are going to design them in CSS.

Let’s go ahead and quickly write styles for these two buttons, starting with .btn

.btn {  
 min-width: 135px;  
 min-height: 45px;  
 font-family: 'Poppins', sans-serif; 
 font-size: 18px;  
 font-weight: bold;  
 letter-spacing: 1.3px;  
 color: #0177db;  
 background-color: #FFF;  
 border: 2px solid #0177db;  
 border-radius: 4px;   
 padding: 5px 20px;  
 cursor: pointer;  
}

That’s a reasonably simple block of CSS code.

Now let’s move to the styles for .btn-solid

.btn-solid {  
 min-width: 135px;  
 min-height: 45px;  
 font-family: 'Poppins', sans-serif;   
 font-size: 18px;  
 font-weight: bold;  
 letter-spacing: 1.3px;  
 color: #FFF;  
 background-color: #0177db;
 border: 2px solid #0177db;  
 border-radius: 4px;   
 padding: 5px 20px;  
 cursor: pointer;  
}

As you might have already noticed, other than two properties(color and background-color) , all the other styles in .btn-solid are identical to that of .btn

 color: #FFF;  
 background-color: #0177db;

And If you are familiar with Sass, you may know that .btn-solid styles can be rewritten in SASS like so:

.btn-solid {  
 @extend .btn;  
 color: #FFF;  
 background-color: #0177db;  
}
.btn-solid is a specialized version of .btn

.btn-solid is a specialized version of .btn

So, .btn-solid is a specialized version of .btn

As you can see, .btn-solid inherits styles from .btn, then overrides some of them (font color and background color) to create itself.

Which leads us to the conclusion that .btn-solid is a specialized version of .btn. Or, in other words, .btn-solid is .btn but with different font color and background colors. That makes sense right? But wait there’s more.

Let’s say we want to create a larger button, .btn-lg. We will use .btn as a prototype to supply base styles. Then, similar to how we modified background and font colors to create .btn-solid, we will modify the font-size property to a larger value to create a larger button.

btn-lg is specialized version of btn

Both .btn-lg and .btn-solid are specialized versions of .btn.btn supplies base styles to .btn-lg and .btn-solid which then overwrite some of the base styles to create themselves.

This tells us that a single button that we decide — .btn in our case — can be used as a supplier of base styles to multiple items.

btn can be used as a supplier of base styles to multiple items

In this section, we tried to define the concept of prototypes for CSS buttons. A Prototype is an entity that supplies base styles, which can be extended to create different instances of buttons. This definition of a prototype is very close to what prototypes actually mean in programming terms.

In programming terms, a prototype is an object that supplies base behavior to a second object. The second object then extends this base behavior to form its own specialization.

Let’s see in the next section how our knowledge of prototypes in CSS buttons maps to JavaScript.

Prototypes in JavaScript

Consider the following JavaScript object:

let obj = {  
 a: 1  
};
console.log(obj.a); //1

We know that the value of a can be accessed by obj.a, given that a is clearly a property of obj.

But there’s more, you can also call obj.hasOwnProperty('a') to check if obj actually has a property named a.

let obj = {  
 a: 1  
};
console.log(obj.hasOwnProperty('a')); //true

Now wait a second — from what we can see, obj has no property called hasOwnProperty defined on it.

Where did hasOwnProperty come from? To answer this question we will have to go back to the buttons we just finished creating.

.btn-solid just has background and font colors defined on it. Where is it getting, for example, border-radius from? We know that .btn-solid is a specialization of .btn, so we can see that .btn-solid is getting styles like border-radiuswidthheight, and padding from .btn. Could it be the same with obj?

Just like .btn-solid and .btn-lg get their base styles from .btnobj or any other JavaScript object for that matter receive their base behavior from another object — Object.prototype.

And this Object.prototype has hasOwnProperty defined on it. And as a result, this gives obj access to the hasOwnProperty method — just like .btn-solid had access to .btn‘s border-radius property.

obj is a specialization of Object.Prototype

obj is a specialization of Object.Prototype

This — an object (obj) inheriting its properties and base-behavior from another object (Object.prototype) — is what we call prototypal inheritance. Notice that there is no class involved in the interplay.

But in JavaScript, we do not have the concept of classes. JavaScript has only Objects. To implement inheritance JavaScript makes use of Prototype. The Inheritance is known as Prototype Inheritance.

The actual inner workings of JavaScript prototypes and our CSS “prototypes” are way different. But for the purpose of our analogy, we can ignore how they work behind the scenes.

Object.prototype isn’t the only prototype available in JavaScript.

There’s Array.prototype, Function.prototype, Number.prototype and several others. The job of all these prototypes is to supply base behavior or utility methods to their instances.

For example every array declared in JavaScript has access to .push.sort.forEach, and .map only because of the prototypal linkage. And for the same reason every function has access to .call.apply.bind.

Let’s take one more example:

As we know, we can create an object in JavaScript using an object constructor function.

// constructor function
function Person () {
    this.name = 'Sunil',
    this.age = 23
}
 
// creating objects
const person1 = new Person();
const person2 = new Person();

In the above example, function Person() is an object constructor function. We have created two objects person1 and person2 from it.

As we mentioned previously, in JavaScript, every function and object has a property named prototype by default.

function Person () {
    this.name = 'Sunil',
    this.age = 23
}
 
const person = new Person();
 
// checking the prototype value
console.log(Person.prototype); // { ... }

In the above example, we are trying to access the prototype property of a Person constructor function.

Since the prototype property has no value at the moment, it shows an empty object { … }.

JavaScript Prototype Inheritance

In JavaScript, a prototype can be used to add properties and methods to a constructor function. And objects inherit properties and methods from a prototype.

For example,

// constructor function
function Person () {
    this.name = 'Sunil',
    this.age = 23
}
 
// creating objects
const person1 = new Person();
const person2 = new Person();
 
// adding property to constructor function
Person.prototype.gender = 'male';
 
// prototype value of Person
console.log(Person.prototype);
 
// inheriting the property from prototype
console.log(person1.gender);
console.log(person2.gender);

Output:

{ gender: "male" }
male
male

In the above program, we have added a new property gender to the Person constructor function using:

Person.prototype.gender = 'male';

Then object person1 and person2 inherits the property gender from the prototype property of Person constructor function.

Hence, both objects person1 and person2 can access the gender property.

Kindly note that the syntax to add the property to an object constructor function is:

objectConstructorName.prototype.key = 'value';

Here, Prototype is used to provide additional property to all the objects created from a constructor function.

We can also add new methods to a constructor function using prototype. For example,

// constructor function
function Person () {
    this.name = 'Sunil',
    this.age = 23
}
 
// creating objects
const person1 = new Person();
const person2 = new Person();
 
// adding a method to the constructor function
Person.prototype.greet = function() {
    console.log('hello' + ' ' +  this.name);
}
 
person1.greet(); // hello Sunil
person2.greet(); // hello Sunil

In the above program, a new method greet is added to the Person constructor function using a prototype.

Changing Prototype

If a prototype value is changed, then all the new objects will have the changed property value. All the previously created objects will have the previous value.

For example,

// constructor function
function Person() {
    this.name = 'Sunil'
}
 
// add a property
Person.prototype.age = 20;
 
// creating an object
const person1 = new Person();
 
console.log(person1.age); // 20
 
// changing the property value of prototype
Person.prototype = { age: 50 }
 
// creating new object
const person3 = new Person();
 
console.log(person3.age); // 50
console.log(person1.age); // 20

Kindly note, we should not modify the prototypes of standard JavaScript built-in objects like strings, arrays, etc. It is considered a bad practice.

Prototypes and prototypal inheritance aren’t JavaScript specific. They are a construct that JavaScript uses internally that allows us to use it in our own programs.

Before we look at how exactly we can do that, we need to understand what prototypal chaining is.

Prototypal Chaining

We will need to get back to the buttons analogy for once. Let’s say we want to create a large solid button, .btn-solid-lg:

JavaScript prototypal chaining

The base styles to .btn-solid-lg are supplied by .btn-solid, and .btn-solid-lg overwrites the font-size property to create itself.

Take a closer look though. .btn-solid has just two styles background-color and color (font) defined on it.

This means .btn-solid-lg has just 3 styles for itself: background-color, color, and font-size. Where are widthheightborder-radius coming from?

Ok, here’s a hint:

An indecipherable hint - JavaScript prototypal chaining

If you wanted to create an extra large button .btn-solid-xlg you could do so with .btn-solid-lg as prototype. But how does all of this map to JavaScript?

In JavaScript, you are allowed to create prototype chains too. Once you understand this, you unlock a whole set of tools to write amazingly powerful code. Yes, amazingly powerful.

Let’s see how prototype chains in JavaScript work.

Remember the object we created in the previous section? The one we carefully named obj? Did you know that you can create as many objects as you want with obj as a prototype?

Object.create lets you create a new object from a specified prototype object. This means that we can create another object, obj2, which has obj as its first prototype:

    let obj = {
      a: 1
    };
    console.log(obj.a); //1
    let obj2 = Object.create(obj);

    // Add a property 'b' to obj2
    obj2.b = 2;
    console.log(obj2.a);  //1
    console.log(obj2.b); //2

If you have been following so far, you should realize that even though obj2 doesn’t have a property a defined on it, doing console.log(obj2.a) won’t result in an error, but instead 1 getting logged to the console. Kind of like this:

prototype chain in JavaScript

When obj2 looks for a, it first searches its own properties. If it can’t find the corresponding property, it asks its prototype (obj), where it finally finds a. If such was the case that it still couldn’t find a, the search would continue up the prototype chain until it reaches the last link, Object.prototype.

On the other hand, if a was defined on obj2, it would override all other as if defined on any of its prototypes.

Similar to how .btn-solid overrode .btn‘s color and background-color properties. This is called property overshadowing.

Prototypes are the means of inheritance in JavaScript. The prototype of an object would also have a prototype object. This continues until we reach the top level when there is no prototype object. This is called prototype chaining or prototype chain in JavaScript.

Lets see one more example:

If an object tries to access the same property that is in the constructor function and the prototype object, the object takes the property from the constructor function.

function Person() {
    this.name = 'Sunil'
}
 
// adding property 
Person.prototype.name = 'Anil';
Person.prototype.age = 23
 
const person1 = new Person();
 
console.log(person1.name); // Sunil
console.log(person1.age); // 23

In the above program, a property name is declared in the constructor function and also in the prototype property of the constructor function.

When the program executes, person1.name looks in the constructor function to see if there is a property named name.

Since the constructor function has the name property with value ‘Sunil’, the object takes value from that property.

When the program executes, person1.age looks in the constructor function to see if there is a property named age.

Since the constructor function doesn’t have age property, the program looks into the prototype object of the constructor function and the object inherits property from the prototype object (if available).

But what about the length of prototype chain? Is there a limit?

There’s no limit to the length of prototype chain. There also aren’t any limits on branching.

This means we can create multiple instances with Object.prototype, obj, or obj2 as prototype from our example.

You can branch at each object as many times as you need to

You can branch at each object as many times as you need to

Conclusion

We hope this analogy has helped you better understand prototypes, prototypal chaining and prototypal inheritance in JavaScript.

Thanks for reading and please share this with your fellow devs.

Further Reading

How useful was this post?

Click on a star to rate it!

Average rating 0 / 5. Vote count: 0

No votes so far! Be the first to rate this post.

We are sorry that this post was not useful for you!

Let us improve this post!

Tell us how we can improve this post?

Similar articles you may like

Sunil Pradhan

Hi there đź‘‹ I am a front-end developer passionate about cutting-edge, semantic, pixel-perfect design. Writing helps me to understand things better.

Add comment

Stay Updated

Want to be notified when our article is published? Enter your email address below to be the first to know.

Sunil Pradhan

Hi there đź‘‹ I am a front-end developer passionate about cutting-edge, semantic, pixel-perfect design. Writing helps me to understand things better.