DEV Community

Cover image for A Quick Introduction to JavaScript Prototypal Inheritance
Nazif Barassounon
Nazif Barassounon

Posted on • Updated on • Originally published at nazifbara.com

A Quick Introduction to JavaScript Prototypal Inheritance

The prototypal inheritance is how, in JavaScript, we share reusable properties and methods throughout objects. In this article, we'll see how it works.

Say we represented a user with the following object:

let user = {
  name: 'John Snow',

  getName() {
    return this.name;
  },
};
Enter fullscreen mode Exit fullscreen mode

We want an admin user with the same shape and feature with an additional isAdmin property set to true. Here's how prototypal inheritance helps us achieve this without repeating ourselves:

let user = {
  // ...
};

let admin = Object.create(user);
admin.isAdmin = true; // "isAdmin" is a new property set only in `admin`
admin.name = 'Daenerys Targaryen'; // "name" is an inherited property that is overwritten

console.log(admin.getName()); // Daenerys Targaryen ("getName" is also inherited from `user`)
Enter fullscreen mode Exit fullscreen mode

By calling Object.create(user) we've made user the prototype of admin. It means that we have access to all the properties and methods of user through admin.

Illustration

The Prototype Chain

When we call user.getName() and admin.geName(), two different things happen:

  • We find getName directly in user, but not in admin.
  • For admin, we implicitly go one step further in its prototype (user) to find the elusive getName.

By going one step further to reach a prototype, we're walking through the prototype chain. This chain can expand if we introduce a root user, for example:

let user = {
  //...
};

let admin = Object.create(user);
//...

let root = Object.create(admin);
root.isRoot = true;
root.name = 'Night King';

console.log(root.getName()); // Night King (inherited from `user`)
console.log(root.isAdmin); // true (inherited from `admin`)
console.log(root.isRoot); // true (proper to `root`)
Enter fullscreen mode Exit fullscreen mode

Here, when we lookup root.getName, we walk through the prototype chain until the user prototype.

Illustration

The ES6 class

An ES6 class and its instances also use a prototype behind the scene. When we define a constructor, it stores all of its properties and methods in the prototype property. Let's define a User class and some instances to see that in action:

class User {
  constructor(name) {
    this.name = name;
  }

  getName() {
    return this.name;
  }
}

const user1 = new User('Joe');
const user2 = new User('Kim');

console.log(User.prototype === user1.__proto__); // true
console.log(user1.__proto__ === user2.__proto__); // true
Enter fullscreen mode Exit fullscreen mode

As you can see, the constructor and the instances all share the same prototype. We access the prototype using prototype in the constructor and __proto__ in the instances.

Image description

Wrap up

Sharing properties and methods between objects is important because it allows us to make our code reusable and well-organized. We achieve this in JavaScript through a concept called prototypal inheritance. A prototype is an object referenced by other objects seeking the same properties and methods. A prototype can also have a prototype which in turn has a prototype, and so on, forming the prototype chain. We walk through this chain when a property or method is not found directly in a given object.

Top comments (0)