Inheritance in JavaScript
JavaScript is many things: a functional, dynamic, imperative and structured, etc; programming language. Heck, it can even be used for machine learning.
In this article, we would be looking at a concept on its object-oriented side: Inheritance.
Prerequisites
Before looking into inheritance
, you need to know the object-oriented language paradigm as a prerequisite.
Check here if you want to know more about it or brush up on the concept.
Inheritance in JavaScript
Inheritance what is it about?
Imagine giving birth to a 12-year old son (yes, imagine it), you would notice that he has some behaviors and traits from you (skin and eye color, hair, eats a lot, etc.) and some other ones from your spouse. In other words, he inherited those characteristics from you two, and no one else, why? Because you and your spouse are his parents!
Everyone inherits a trait, personality, or property from someone or something. The same concept can be applied in programming. Inheritance in OOP is the ability of any class to acquire methods or properties from its parent class or base class. This is a powerful core concept in programming that allows programmers to create classes upon existing classes making your work and life easier. Cool isn't it? 😏
Now, inheritance in JavaScript is quite different than the normal OOP class-based inheritance you have in languages like Java or C#. Inheritance in JavaScript is prototype-based and not class-based (check this for more info), the class syntax introduced in ES6 is just syntactic sugar. However, it is easier to write, read, and understand!
Code Example
class Human {
constructor(name) {
this.name = name;
}
walk(place) {
return `${this.name} is walking to ${place}`;
}
eat(food) {
return `${this.name} is eating ${food}`;
}
}
class Boy extends Human {
constructor(name) {
super(name);
}
}
let akin = new Boy("Akin");
//inherited method
console.log(akin.walk("school"));
As you can see above the walk
method was inherited by a boy named Akin
, and the method was called with the akin
object (akin.walk("school")
), logging out his destination to the console with a description.
// Result logged out: Akin is walking to school
Again, the construct above (i.e class Human
) does not make JavaScript class-based, as prototypes are still under the hood.
Classes can be and are used for more cleaner and easy-to-read code or maybe you're used to an object-oriented setting and you're having a hard time adapting. However, in some cases, using classes can lead to errors when using the this
keyword on the constructor of classes as it may not perform as expected, hence, it's advised we use prototypes instead.
Prototype Chain
— ECMAScript 2019 Language
Every object in JavaScript has a private property that holds a link to another object called its prototype, and also has a prototype of its own, and so on until it reaches a null value. This null value is only reached when you try and access the prototype of the Object class.
Note: Almost all objects in JavaScript are instances of the Object class, except for primitives like Boolean, Strings, etc.
Here is what inheritance with the prototype chain looks like (please run on the browser console).
let Person = {
name: "",
age: 0,
walk: function(){
console.log("walking");
}
}
let Micheal = Object.create(Person);
Micheal.name = "Hassan";
Micheal.walk = function(place){
console.log(`Walking to ${place}`)
}
Micheal.work = function(work){
console.log(`${this.name} works at ${work}`);
}
Micheal.name = "Micheal";
console.log(Micheal.__proto__);
console.log(Micheal.age);
/**
Results:
{name: "", age: 0, walk: ƒ}
age: 0
name: ""
walk: ƒ ()
__proto__:
constructor: ƒ Object()
hasOwnProperty: ƒ hasOwnProperty()
isPrototypeOf: ƒ isPrototypeOf()
...
0
**/
The first line creates an object called Person
which has some default properties and a method. Next, I use Object.create to create an object Micheal
from an existing object Person
as the prototype of Micheal
. Micheal
, therefore, inherits all the default properties and functions in the Person
object which I can now override with custom properties.
But be careful to override all needed properties from the Person
object, lest if the property is called it will revert to its ancestor default property (which is 0 in our case!).
Note: If the JavaScript’s interpreter doesn’t find a specified property [like address] in the
Micheal
object; it searches through its ancestor for that property and if it is still not found, it searches through the ancestor prototype of that prototype and so on till it reaches an eventualnull
value.
Example: (Still using the Micheal
object example above)
console.log(Micheal.__proto__);
console.log(Micheal.__proto__.__proto__);
console.log(Micheal.__proto__.__proto__.__proto__);
/**
Results:
{name: "", age: 0, walk: ƒ}
{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ,
…
}
null
**/
Imagine you constantly use a particular function like reading from different files, you can easily create your own library built from prototypes and easily manipulate it anywhere in your code to suit your needs for any file type. Just inherit the properties and override any void methods if needed and you are good to go!
Thank you for reading this article on inheritance in JavaScript!