Inheritance in JavaScript object-oriented programming
Tags: webdev, javascript, oop, programming
Published: 2022-11-24 00:43:22

by [Nwakor Chidinma Favour](https://blog.openreplay.com/authors/nwakor-chidinma-favour)

Inheritance in JavaScript Object-Oriented Programming (OOP) is a fundamental concept that has evolved over time, and in this article we'll show how it works and how to use it.

We're looking at true class inheritance, not simply prototypal inheritance between instances. The class terminology is used here only to make it simpler to grasp what we're going to do. Here's what we're going to do, we'll construct a new student class that inherits from the person class. The parent class will be a person, and the child class will be a student. This is because a student is essentially a subtype of a person. 

A student is a person, a more specific individual, and this relationship is essentially the inheritance concept that we'll explore in this article. To begin, we will use `constructor` functions. We will inherit across classes using constructor functions in the first phase, which will need some work but will help you understand exactly how the prototype chain is built up to allow inheritance between the prototype properties of two separate constructor functions. Then, in the following step, we'll perform the same using ES6 classes, which will be much easier.

Finally, we shall make use of `object.create`. Let's put this into action right now.


## Inheritance between "Classes": Constructor functions


A  [constructor function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/constructor)  is being built for the student. We want the child class to have the same functionality as the parent class but with some additional functionality. We pass the same argument into the child class but then some additional ones.

```javascript
const person = function (firstName, birthYear) {
  this.firstName = firstName;
  this.birthYear = birthYear;
};

person.prototype.calcAge = function () {
  console.log(2022 - this.birthYear);
};

const student = function (firstName, birthYear, course) {
  this.firstName = firstName;
  this.birthYear = birthYear;
  this.course = course;
};
```

The above shows that the `student` class has almost the same data as the `Person`. 

We can then create a new student. 

```javascript
const paul = new student("Paul", 2010, "Computer Science");
console.log(paul);
```

We can also add a method by modifying the [prototype property](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes).

```javascript
//Add in a method
student.prototype.introduce = function () {
  console.log(`My name is ${this.firstName} and I study ${this.course}`);
};

paul.introduce();
```

So far, this is what we've created. It is nothing more than the student constructor function and its prototype attribute. In addition, the `paul` object is connected to its prototype, and, of course, the prototype is the constructor function's prototype attribute. By constructing the `paul` object using the new operator, this relationship between instance and prototype is now created automatically.

We are going to have to create this connection manually. To link these two prototype objects, we will use [object.create](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create)  because defining prototypes manually is precisely what `object.create` does. A student is a person; as a result, we want student and person to be linked. We are interested in the student class being a child class descended from the person class, the parent class. As a result, all occurrences of students will get access to everything in the prototype property, such as the `calcAge` function. That is the whole point of inheritance. The parent classes can share their conduct with their child classes. 

We want to make `person.prototype` the prototype of `student.prototype` or, in other words, we want to set the proto property of `student.prototype` to `person.prototype`. We are going to have to create this connection manually. We will use `object.create` to link these two prototype objects because defining prototypes is exactly what `object.create` does. With this, the `student.prototype` object is now inheriting from the `person.prototype`. Now we have to create this connection before adding more methods to the prototype object of a student. That's because `object.create` will return an empty object. At this point, `student.prototype` is empty. Then onto that empty object, we can add methods.


Now, with all this in place, we can call the `calcAge` method even in a child class.


```javascript
const person = function (firstName, birthYear) {
  this.firstName = firstName;
  this.birthYear = birthYear;
};

person.prototype.calcAge = function () {
  console.log(2022 - this.birthYear);
};

const student = function (firstName, birthYear, course) {
  person.call(this, firstName, birthYear);
  this.course = course;
};

//Linking Prototypes
student.prototype = Object.create(person.prototype);
//Add in a method
student.prototype.introduce = function () {
  console.log(`My name is ${this.firstName} and i study ${this.course}`);
};

const paul = new student("Paul", 2010, "Computer Science");
paul.introduce();
paul.calcAge();
```

We already know this worked because of the prototype chain but let's see precisely how. When we do `paul.calcAge()`, we effectively do a property or a method lookup, JavaScript trying to find the requested property or method. The `calcAge` method is not directly on the `paul` object and is also not in `paul`'s prototype. Whenever we try to access a method not on the object or its prototype, JavaScript will look up even further in the prototype chain. JavaScript will finally find `calcAge` in `person.prototype`. That's the whole reason why we set up the prototype chain like this so that the `paul` object can inherit whatever methods are in its parent class. In summary, we can now call a method on a person's prototype property, on a student object, and it still works. **That's the power of inheritance**.

So just like before, `object.prototype` will sit on top of the prototype chain. It doesn't matter how far away in the prototype chain a method is; with this, we now have the full picture of how inheritance between classes works with function constructors.




<h2>Open Source Session Replay</h2> 

_<a href="https://github.com/openreplay/openreplay" target="_blank">OpenReplay</a> is an open-source, session replay suite that lets you see what users do on your web app, helping you troubleshoot issues faster. OpenReplay is self-hosted for full control over your data._

![OpenReplay](https://blog.openreplay.com/banner-blog_1oYPGT.png)

_Start enjoying your debugging experience - <a href="https://github.com/openreplay/openreplay" >start using OpenReplay for free</a>._





## Inheritance between "Classes": ES6 Classes

It works the same internally with [ES6 classes](https://hacks.mozilla.org/2015/07/es6-in-depth-classes/); all that changes is the syntax.

Let's copy the initial `person` class that we built earlier. So, we can inherit from the class.

```javascript
const steven = Object.create(personProto);
const studentProto = Object.create(personProto);
class personCl {
  constructor(fullName, birthYear) {
    this.fullName = fullName;
    this.birthYear = birthYear;
  }

  calcAge() {
    console.log(2022 - birthYear);
  }
}
```

The `class` syntax hides a lot of the details happening behind the scenes because classes are just a layer of obstruction over constructor functions. To implement inheritance between ES6 classes, we only need two ingredients, which are the  [extends](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends#:~:text=The%20extends%20keyword%20can%20be,candidate%20for%20the%20parent%20class.&text=The%20prototype%20of%20the%20ParentClass%20must%20be%20an%20Object%20or%20null%20.) keywords and the  [super](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super#:~:text=The%20super%20keyword%20is%20used,both%20classes%20and%20object%20literals.)  function. 


The `extends` keyword alone will link to prototypes behind the scenes without even thinking about that. Then, of course, we still need a constructor. This will be like before, receive the same arguments as the parent class, plus some additional ones like `birthYear` and `course`. We don't need to manually call `personCl.call` as we did before in the constructor function. What we do instead is to call the `super` function. The super function is the constructor function of the parent class. The idea is still similar to what we did in the constructor function, but it all happens automatically here. We don't need to specify the name of the parent class again because that has already happened. All we do is pass in the arguments for the parent class constructor.


The call to the super function always needs to happen first because the call to the super function is responsible for creating the `this` keyword in the subclass. Still, the additional parameter and argument are not mandatory.

```javascript
class studentCl extends personCl {
  constructor(fullName, birthYear, course) {
    //Always needs to happen first
    super(fullName, birthYear);
    this.course = course;
  }

  introduce() {
    console.log(`My name is ${this.fullName} and i study ${this.course}`);
  }
}
```
Now let's create a new student,

```javascript
const martha = new studentCl ('Martha', 2012, 'computer science')
```
Now, we can call the `calcAge` method and the `introduce` method.

```javascript
martha.introduce();
martha.calcAge();
```

If we look at Martha's prototype, we can see that the `introduce` and `calcAge` methods are there. This proves that the prototype chain was set up automatically by basically this `extends` keyword here.



## Inheritance between "Classes": Object.create

Now, let's create an object that will serve as a prototype to create a new person object using `object.create`. This will be our parent class.

`Object.create` is easier to use and understand, and it won't be hard to implement a similar hierarchy between a person and a student.  

```javascript
const personProto = {
  calcAge() {
    console.log(2022 - this.birthYear);
  },

  init(firstName, birthYear) {
    this.firstName = firstName;
    this.birthYear = birthYear;
  },
};
```
The `personProto` is the prototype of all the new person objects, but now we want to add another prototype in the middle of the chain. That's between `personProto` and the object. We are going to make students inherit directly from person, and we will create an object that will be the prototype for students.


```javascript
const studentProto = Object.create(personProto);
//we can use this student proto to create new students
const ray = Object.create(studentProto);
```

The `studentProto` object that we just created earlier is now the prototype of the `ray` object. Again, the studentProto object is now the prototype of `ray,` and the `personProto` object is, in turn, the prototype of `studentProto`. Therefore, `personProto` is a parent prototype of `ray`, which means it's in its prototype chain.

It all starts with the PersonProto object, which used to be the prototype of all `person` objects but now using `Object.create`, we make it so that `personProto` will become the prototype of `studentProto` and what this does is that basically, student inherits from person. We already established the parent-child relationship that we were looking for. To finish, all we need to do is use `Object.create` again, but this time to create a new actual student object. `ray` inherits from `studentProto`, which is now `ray`'s prototype; therefore, the `ray` object will be able to use all the methods in `studentProto` and `personProto`.

With the scope chain correctly established, let's also add an `init` method to studentProto, which will receive the `firstName`, `birthYear`, and `course` just like we did here with `personProto` so that we don't have to manually specify the properties on any new student object. 

```javascript
studentProto.init = function (firstName, birthYear, course) {
  personProto.init.call(this, firstName, birthYear);
  this.course = course;
};

studentProto.introduce = function () {
  console.log(`My name is ${this.firstName} and i study ${this.course}`);
};

const ray = Object.create(studentProto);
ray.init("Ray", 2010, "computer science");
ray.introduce();
ray.calcAge();
```


If we look at the prototype of `ray`, we can see that the `init` and `introduce` methods are there. Then inside the inner prototype, the `calcAge` method can be found. In this `Object.create` we don't worry about the constructor function or prototype properties, and it's just objects linked to other objects. This is simple and beautiful if you ask me. In fact, some people think that this pattern is a lot better than basically trying to fake classes in JavaScript because faking classes in the way that they exist in other languages like Java or C++ is precisely what we do by using constructor functions and even ES6 classes. But here, in this technique that I just showed you with `Object.create`, We are, in fact, not faking classes.

We are simply linking objects together, where some objects then serve as the prototype of other objects. I wouldn't mind if this were the only way of doing OOP in JavaScript, but ES6 classes and `constructor`s are way more used in the real world. However, it's still super important and valuable that you learn these three techniques now because you will see them all. This also allows you to think about this and choose the style you like the best. 

## Conclusion
Inheritance lets you design a class that inherits all of the functionality of a parent class and adds new capabilities. A class can inherit all of the methods and attributes of another class via class inheritance. In JavaScript, inheritance is supported by using prototype objects, and inheritance is a helpful feature that enables code reuse.

I hope you found this article on the inheritance Concept in JavaScript useful!



[![newsletter](https://blog.openreplay.com/newsletter_Z1P0UIP.png)](https://newsletter.openreplay.com/)