Prototypal Inheritance in JavaScript

Prototypal: JavaScript is unique in a lot of ways. It’s the major browser-supported language that powers most user interfaces online. It has its own quirks in syntax and equality that can range from endearing to maddeningly annoying. However, JavaScript’s biggest unique point is object inheritance and the prototype chain.

In nearly any interview for a front-end or JavaScript developer role, you’re likely to hear a question about prototypal inheritance, and for good reason. Inheritance is a critical concept in computer programming, and JavaScript inheritance works unlike any other programming language. Even experienced developers can get tripped up by the JavaScript prototype chain, its mechanics, and how it differs from other programming languages.

 

In this outline, we will cover the essentials on prototypal inheritance in JavaScript.

Quick Recap: What Is Inheritance?

In most object-oriented programming languages, there is a mechanism for child objects to inherit methods and attributes from their parents. Popular languages like Java, C#, C++, and Python (among many others) all support this type of inheritance. Defining these objects and their inheritance structures is a matter of creating classes that extend one another. A class is a definition of attributes and behaviors, an object is an instance of a given class.

For instance, you might have a base Animal class with methods that allow animals to eat() and sleep(). Then, your Dog class inherits the eat() and sleep() methods from its Animal parent class while also defining its own methods like bark() and be_undyingly_loyal().

Inheritance is one of the core principles of object-oriented design. It helps build reusable and modular components of software applications because we can inherit from and extend the parent class in many different ways.

Inheritance

in JavaScript
It’s possible to do object-oriented programming in JavaScript. Indeed, JavaScript has built-in support for inheritance between objects.

However, JavaScript is not a class-based language. While there is a class keyword in JavaScript since 2015, it’s only syntactic sugar. Under the hood, JavaScript has its own mechanism for defining and resolving inheritance relationships.

This mechanism is known as the prototype chain. There are two key things to know about the JavaScript prototype chain and how it differs from class-based languages. If you take nothing else from this article, these two points will get you pretty far in understanding JavaScript inheritance.

1. Prototypes are objects themselves

In class-based languages, the classes act as blueprints. No object of that class actually exists until you instantiate it in your program. So, you define the class, then you create an instance of that class.

In JavaScript, prototypes are objects themselves. In fact, every function in JavaScript has a __proto__ attribute and a special property called `prototype` that allows you to access the __proto__ attributes.

If you open your console in your browser (ctrl+shift+I in Chrome & Firefox), you can see this for yourself.

Let’s create a new function that does absolutely nothing. Just leave it empty:

ZnVuY3Rpb24gZG9Tb21ldGhpbmcoKXt9

Then, let’s check out the default prototype property that JavaScript created for us:

Y29uc29sZS5sb2coIGRvU29tZXRoaW5nLnByb3RvdHlwZSApOw==
You can see the constructor for the doSomething function is indeed doSomething(). However, every JavaScript function also inherits certain attributes and qualities from JavaScript’s default Object() prototype. So, you can see all those default methods as well.

ewogICAgY29uc3RydWN0b3I6IMaSIGRvU29tZXRoaW5nKCksCiAgICBfX3Byb3RvX186IHsKICAgICAgICBjb25zdHJ1Y3RvcjogxpIgT2JqZWN0KCksCiAgICAgICAgaGFzT3duUHJvcGVydHk6IMaSIGhhc093blByb3BlcnR5KCksCiAgICAgICAgaXNQcm90b3R5cGVPZjogxpIgaXNQcm90b3R5cGVPZigpLAogICAgICAgIHByb3BlcnR5SXNFbnVtZXJhYmxlOiDGkiBwcm9wZXJ0eUlzRW51bWVyYWJsZSgpLAogICAgICAgIHRvTG9jYWxlU3RyaW5nOiDGkiB0b0xvY2FsZVN0cmluZygpLAogICAgICAgIHRvU3RyaW5nOiDGkiB0b1N0cmluZygpLAogICAgICAgIHZhbHVlT2Y6IMaSIHZhbHVlT2YoKQogICAgfQp9

We can add data and methods to our doSomething prototype by setting them using .prototype:

ZG9Tb21ldGhpbmcucHJvdG90eXBlLmZvbyA9ICJiYXIiOw==

Then, if we look at the results of console.log( doSomething.prototype ); again we can see that new value:

ewogICAgZm9vOiAiYmFyIiwKICAgIGNvbnN0cnVjdG9yOiDGkiBkb1NvbWV0aGluZygpLAogICAgX19wcm90b19fOiB7CiAgICAgICAgY29uc3RydWN0b3I6IMaSIE9iamVjdCgpLAogICAgICAgIC4uLiAvLyBvdGhlciBkZWZhdWx0IG1ldGhvZHMgaGVyZQogICAgfQp9
Cool! So we see doSomething is an object itself. We can define methods/data on doSomething’s prototype. We can also see the methods and data from doSomething’s parent prototype – Object().

2. JavaScript prototypal inheritance relationships are created/resolved on-the-fly at the time of interpretation

JavaScript is designed to run inside browsers, so it isn’t compiled and it needs to be simple to interpret and resolve at runtime.

The prototype chain keeps things simple by making everything a first-class object. Instead of class blueprints that can inherit once they’re instantiated as real objects, JavaScript just chains objects together to form inheritance relationships.

That might be a confusing sentence to read, and sometimes JavaScript’s chaining rules are confusing, so let’s look at an example:

bGV0IEFuaW1hbCA9IGZ1bmN0aW9uIChuYW1lKSB7IC8vIGNyZWF0ZSBhbiBBbmltYWwgYmFzZSBwcm90b3R5cGUKICAgIHRoaXMubmFtZSA9IG5hbWUgLy8gc2V0IEFuaW1hbCBhdHRyaWJ1dGVzIHVzaW5nIHRoZSDigJx0aGlz4oCdIGtleXdvcmQgb24gQW5pbWFsCn0KQW5pbWFsLnByb3RvdHlwZS5lYXQgPSBmdW5jdGlvbiAoKSB7IC8vIGFkZCBBbmltYWwgcHJvdG90eXBlIG1ldGhvZHMKICAgIGNvbnNvbGUubG9nKGAke3RoaXMubmFtZX0gaXMgZWF0aW5nYCkgCn0KbGV0IERvZyA9IGZ1bmN0aW9uIChuYW1lLCBicmVlZCkgeyAvLyBjcmVhdGUgYSBEb2cgc3ViLXByb3RvdHlwZQogICAgQW5pbWFsLmNhbGwodGhpcywgbmFtZSkgLy8gY2FsbCB0aGUgQW5pbWFsIG9iamVjdCBhcyBhIGNvbnN0cnVjdG9yCiAgICB0aGlzLmJyZWVkID0gYnJlZWQgLy8gc2V0IERvZyBhdHRyaWJ1dGVzIHVzaW5nIHRoZSDigJx0aGlz4oCdIGtleXdvcmQgb24gRG9nCn0KRG9nLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoQW5pbWFsLnByb3RvdHlwZSkgLy8gZ2l2ZSBEb2cgYWNjZXNzIHRvIEFuaW1hbCBtZXRob2RzCkRvZy5wcm90b3R5cGUuYmFyayA9IGZ1bmN0aW9uICgpIHsgY29uc29sZS5sb2co4oCYV29vZiB3b29mIeKAmSkgfSAvLyBhZGQgRG9nLXNwZWNpZmljIG1ldGhvZHMKRG9nLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IERvZyAvLyByZXNldCBjb25zdHJ1Y3RvciBmb3IgbmV3IGRvZ3MgdG8gYmUgRG9nIGluc3RlYWQgb2YgQW5pbWFsCmZpZG8gPSBuZXcgRG9nKOKAmEZpZG/igJksIOKAmFBvaW50ZXLigJkpIC8vIHRoZSDigJxuZXfigJ0ga2V5d29yZCBqdXN0IGNyZWF0ZXMgYSBjb3B5IG9mIHRoZSBEb2cgZnVuY3Rpb24gJiBjYWxscyBpdApmaWRvLm5hbWUgLy8g4oCcRmlkb+KAnSBmcm9tIEFuaW1hbCA+PiB0aGlzLm5hbWUKZmlkby5icmVlZCAvLyDigJxQb2ludGVy4oCdIGZyb20gRG9nID4+IHRoaXMuYnJlZWQKZmlkby5lYXQoKSAvLyDigJxGaWRvIGlzIGVhdGluZ+KAnSBmcm9tIEFuaW1hbC5wcm90b3R5cGUuZWF0CmZpZG8uYmFyaygpIC8vIOKAnFdvb2Ygd29vZiHigJ0gZnJvbSBEb2cucHJvdG90eXBlLmJhcms=
Hopefully you can see how functions inherit from each other in this example. Ultimately, fido is just a copy of Dog, which in turn is a copy of Animal that’s called within the this-context of Dog.

If we look at fido’s prototype inheritance chain we can see these relationships:

fido.__proto__

  • Animal {bark: ƒ, constructor: ƒ}
    • bark: ƒ () <– Dog’s bark method
    • constructor: ƒ (name, breed) <– Dog’s arguments for setting breed attribute
      • arguments: null
      • caller: null
      • length: 2
      • name: “Dog”
      • prototype: Animal {bark: ƒ, constructor: ƒ}
      • __proto__: ƒ ()
      • [[Scopes]]: Scopes[2]
    • __proto__:
      • eat: ƒ () <– Animal’s eat method
      • constructor: ƒ (name) <– Animal argument for setting name attribute
      • __proto__: Object

When JavaScript finds that fido itself doesn’t have an eat method, it checks fido’s parent, Dog.prototype, methods. When Dog.prototype also doesn’t have an eat method, it checks Dog’s parent, Animal.prototype, where it finds the eat method.

 

Using the class

Keyword
Since ECMA 2016, JavaScript has included a “class” keyword so that developers don’t have to bother with Object.create(), Instance.prototype.constructor, and ParentInstance.call().

When you use the class keyword, what’s really happening is what we see above. However, the class keyword makes it much easier to write. Now you can say:

Y2xhc3MgQW5pbWFsIHsKICAgIGNvbnN0cnVjdG9yKG5hbWUpIHsKICAgICAgICB0aGlzLm5hbWUgPSBuYW1lCiAgICB9CiAgICBlYXQoKSB7CiAgICAgICAgY29uc29sZS5sb2coYCR7dGhpcy5uYW1lfSBpcyBlYXRpbmdgKQogICAgfQp9CiAKY2xhc3MgRG9nIGV4dGVuZHMgQW5pbWFsIHsKICAgIGNvbnN0cnVjdG9yKG5hbWUsIGJyZWVkKSB7CiAgICAgICAgc3VwZXIobmFtZSkgLy8gaW5pdGlhbGl6ZSB0aGUgcGFyZW50IGNsYXNzCiAgICAgICAgdGhpcy5icmVlZCA9IGJyZWVkCiAgICB9CiAgICBiYXJrKCkgewogICAgICAgIGNvbnNvbGUubG9nKOKAmFdvb2Ygd29vZuKAmSkKICAgIH0KfQ==
And that’s it! The class keyword makes inheritance much easier.
Conclusion

Prototypal Inheritance in JavaScript

For JavaScript developers, it’s critical to know what your language is doing behind the scenes when you’re inheriting attributes and methods from one object to another. For developers who are familiar with other languages and new to JavaScript, understanding the prototype chain is going to be essential to getting stuff done.

The Fastest Way To Build Software Is “Right” The First Time!

 

Intertech Logo

 

Understanding your industry is one thing. Understanding the technology you are using is another. When you read studies that tell you that 75% of projects are doomed from the beginning, it has to make you pause before signing your name to the outcome.

Consider letting our proven professionals take a look at your project. They’ve seen what can go wrong and know how to avoid costly errors.

We build custom software from start to finish. We plug into your environment with the proven expertise you need for us to work independently or in co-development. And, we bring the soft-skills that make the task enjoyable, and the experience to leave your team stronger and ready to take over.

We Bring You…

Team-Complete™ Development

Intertech’s Team-Complete™ development means we make sure all the right people are seated at the table to assure success the first time. At Intertech, you always get the best of the best! Proven consultants dive deep into your project, analyze your objectives, and lead your project to success with the expertise and the soft-skills you expect from a leader.

Soft-Skills For A Winning Experience

Sometimes the most critical person in the room is the one with a calm voice and the knowledge to select the right words. Bringing a development team together or presenting a clear concept for stakeholders can make all the difference between success or failure. Intertech consultants are at the top of their field. They navigate challenging decisions, guide with a confident voice, and know when to get out of the way.

Turn to Intertech when you need it done right!

Intertech takes the worry out of custom software development.
Discover All That Intertech Can Do For You!

Let’s Build Something Great!

Tell us what you need and we’ll get back with you ASAP!