Inheritance in JavaScript - Part 1 of 3
© https://commons.wikimedia.org

Inheritance in JavaScript - Part 1 of 3

Inheritance in prototype-based Javascript explained

ByMario Kandut

honey pot logo

Europe’s developer-focused job platform

Let companies apply to you

Developer-focused, salary and tech stack upfront.

Just one profile, no job applications!

Compared to class-based languages like Java, C# or C++, JavaScript is a bit different. JavaScript is dynamic and doesn't provide a class implementation. Though, there is the class keyword, which was introduced in ES2015, but its just syntactical sugar. JavaScript remains prototype-based.

The prototype chain

When it comes to inheritance, JavaScript only has one construct: objects. Each object has a private property which holds a link to another object called its prototype. That object also has a prototype on its own, and that object also and the next one and so on, until an object is reached with NULL as its prototype. By definition, null has no prototype, so it is the final link in this prototype chain.

💰 The Pragmatic Programmer: journey to mastery. 💰 One of the best books in software development, sold over 200,000 times.

As we can see now the prototype chain, inheritance in JavaScript is achieved with a chain of prototypes. There are different approaches on creating prototype chains. They have evolved over time as the languages updates and new features and syntax are added. Nearly all objects in JavaScript are instances of Object which sits on the top of a prototype chain.

The prototypal inheritance model itself is more powerful than the classic model. For example, it is fairly simple to build a classic model on top of a prototypal model.

There are three common ways to create a prototype chain:

This article will cover the functional approach on creating prototype chains.

Prototypal Inheritance (Functional)

The functional approach to creating prototype chains is to use Object.create. Let's have a look at an example. For the example code, we will use the animal and dog taxonomy, where animal is a prototype of dog.

const animal = {
  eat: function() {
    console.log(this.name + ' eats');
  },
};

const dog = Object.create(animal, {
  bark: {
    value: function() {
      console.log(this.name + ' woofs');
    },
  },
});

const henry = Object.create(dog, {
  name: { value: 'Henry' },
});

henry.bark();
henry.eat();

The animal is a plain JavaScript object, created with the object literal syntax, and the prototype is Object.prototype, as for every plain JavaScript object. The Object.create function takes two arguments. First one is the desired prototype of the object being created, and the second one is the properties you want to add or the Properties Descriptor Object, it's optional.

So, when dog is instantiated, the first argument is the animal object. So animal is the prototype of dog. When henry is instantiated the first argument is dog passed to Object.create is dog. So the full prototype chain ist:

  • the prototype of henry is dog
  • the prototype of dog is animal
  • the prototype of animal is Object.prototype.

The Property Descriptor is a JavaScript object that describes the characteristics of the properties on another object, and contains keys that will become the key name on the object being created.

The values of these keys are called Property Descriptor objects. The method Object.getOwnPropertyDescriptor can be used to get a property descriptor on any object. To describe the value of a property, the descriptor can either use value or get and set to create a property getter/setter. The other properties are associated meta-data for the property. There is a writable property that determines whether the property can be reassigned, and a enumerable property, which determines whether the property will be enumerated in property iterator abstractions (like Object.keys). The configurable property sets whether the property descriptor itself can be altered. The default for all of these meta-data keys is false. Read more about property descriptors at MDN.

In the case of dog and henry the property descriptor only sets value, which adds a non-enumerable, non-writable, non-configurable property.

The JavaScript runtime performs the following steps when henry.eat is called.

  • Check if henry has a eat property; (NO)
  • Check if the prototype of henry, which is dog, has a eat property (NO)
  • Check if the prototype of dog, which is animal, has a eat property (YES)
  • Execute the eat function setting this to henry, so this.name will be 'Henry'.

TL;DR

  • Inheritance in JavaScript is achieved with a chain of prototypes
  • There are three common ways to create a prototype chain (functional, constructor functions, class-syntax constructors)

Thanks for reading and if you have any questions, use the comment function or send me a message @mariokandut.

If you want to know more about Javascript, have a look at these Javascript Tutorials.

References (and Big thanks)

MDN, JSNAD

Scroll to top ↑