JavaScript — Prototypal Inheritance [RuleBook]

Ravi Roshan
8 min readOct 24, 2017

--

JavaScript [[Prototypal]] Inheritance — Code Flow & Prototype Linkage

So, if you have landed here to understand what is Prototypal Inheritance in JavaScript, I am assuming that you have a good understanding of Inheritance [Basic OOPS concept].

Switching my career to JavaScript from C++, Java, C# or any other programming language which supports the classical inheritance, JavaScript Inheritance looked pretty weird at the first glance.
To be frank, it is the same case for any seasonal JS developer.

But if you are really serious about your career in JavaScript which is taking over the complete landscape of Web development or even server side, further reaching to Mobile app development, it’s really important to understand few of the basic and core concept of JS — Inheritance, Closure, Promises, Threading Modal, etc.

In this article, we will be covering the very first concept — ‘Prototypal Inheritance in JavaScript’.

As JavaScript doesn't have any class structure and native support for it — you can have completely 2 different view on Classes in JavaScript.
whether it is a Class-Less language or a Class-Free language.

I am more inclined towards the later one as it gives you more flexibility to define your inheritance structure without getting too strict about the initial skeleton. But with more power, you get more responsibility 😎.

Note ⚠️ : ES6 i.e. EcmaScript 2015 introduced class keyword in the latest version of JavaScript, but it is just syntactical sugar over JavaScript’s existing prototype-based inheritance to fake the Class like structural syntax.

In case of JavaScript — a “class” consist of two important parts :

1. Function as Constructor: This function contains all the logic to create an instance of the “class”, i.e. instance specific code what we call as an object.
Basically the code inside the function which will be executed when called with the new keyword.

2. Prototype object : An object containing the properties & methods that the Initiated Object will be inheriting by default. It is attached to the class, not to the Initiated Object and shared across all the object. You can think of it as static members in Java/C#.

Let’s say, you want to create a class Person with two properties name and age.

function PersonClass(name, age){
this.name = name;
this.age = age;
}
var person1 = new PersonClass('John', 26);// Output
{
age: 26,
name: "John"
}

Now, let’s add one method — walk() on PersonClass

function PersonClass(name, age) {
this.name = name;
this.age = age;
this.walk = function() {
console.log('Person ' + this.name + ' is walking');
}
}
var person1 = new PersonClass('John', 26);
// Output
{
age: 26,
name: "John",
walk: [Function]
}
// Output : person1.walk()
Person John is walking

You can see that keeping a method inside a class will create a separate copy of it for each class instance— object person1.

It is really not required as it will have a higher memory footprint and should be shared across the instances.♻️

One easy solution to this problem is : put the method on Class Prototype object.

function PersonClass(name, age) {
this.name = name;
this.age = age;
}
PersonClass.prototype.walk = function() {
console.log('Person ' + this.name + ' is walking');
}
var person1 = new PersonClass('John', 26);// Output : person1
{
age: 26,
name: "John"
}
// Output : person1.walk()
Person John is walking

Hold on, what the hack is this prototype property attached to PersonClass function ⁉️

In JavaScript, functions are first-class OBJECTS, because they can have properties and methods just like any other object. 😳😳

// example
function foo() {/* Execution Code */}
foo.createdBy = 'John';
foo.getCreatorDetails = function() {
return 'John is Developer';
}
// Output
foo.createdBy ==> 'John'
foo.getCreatorDetails ==> 'John is Developer'

So in above case prototype is just a property on PersonClass.

Rule 1 : By default all function in JavaScript gets a public, nonenumerable property on them called prototype, which points at an object.

The prototype property object on the function has two internal properties attached to it i.e.

  1. constructor fn() : which refers to the function itself.
  2. __proto__ {} : which refers to the global Object.prototype.
PersonClass
|--Execution Code
|--prototype Object
|--constructor : fn() refers to PersonClass itself.
|--__proto__ : refers to Object.prototype

Rule 2 : All the Objects in JavaScript will have __proto__ property [default set to the global Object.prototype] except when created using Object.create(null);

Let’s instantiate the PersonClass as constructor function i..e calling it with the new keyword.

var person1 = new PersonClass('John', 26);

The above line of code performs the following steps under the hood :

  1. The new keyword prefixed before function call will create an empty object {} out of thin air.
  2. __proto__ of the newly created object is changed from default Object.prototype to PersonClass.prototype i.e. simple linking.🔗
  3. The THIS keyword inside the function will refer the passed object.
  4. Different properties and methods gets added to the passed object [this.name = name, this.age = age].
  5. The modified object is returned implicitly if NO Explicit return object is present in the function.
  6. The return object is assigned to person1 variable.

You can verify that the person1.__proto is reffering to PersonClass.prototype with the following code :

person1.__proto__ === PersonClass.prototype // true

So, till now we have understood and created an Object person1 from Function constructor PersonClass. This way, we can fake the class system in JavaScript and create instances of it.

var person2 = new PersonClass('Doe', 40);
var person3 = new PersonClass('Harry', 18);
// person2.walk();
// Person Doe is walking
// person3.walk();
// Person Harry is walking

Any property or method attached to a Function’s prototype object property will be by default available to any Object Instance created using that Function as constructor.

var userName = “John”;
userName.length; // Output: 4
var fruitsArray = ['Kiwi', 'Apple', 'Banana']
fruitsArray.sort(); // Output: ['Apple', 'Banana' Kiwi']

As you can see, we just created userName and fruitsArray variables and then immediately were able to use length & sort() respectively.
This was possible because .length & sort() is available on String & Array Native constructor. [Refer the top diagram]

Now, let’s move to the next part — Inheritance 📣

In case of Classical inheritance which is supported by C++/Java/C#, you create a PARENT Class and extend it to the CHILD. The properties & methods of the Parent class will be then accessible to any Object initiated from the Child class.
Further the properties can be overridden in child as per requirements.

But JavaScript doesn’t have class structure itself. Whatever we achieved in the above code is just by simulating a function constructor to create an object.

Rule 3 : JavaScript works on principal of Prototypal inheritance instead of classical inheritance i.e. a child object links to a parent object using [[Prototype]] chain to utilize the parent’s methods and properties.

Let’s try creating a Person and Employee inheritance hierarchy here. As we already have a function constructor for PersonClass which is generating person object, we will write similar code for EmployeeClass also.

function EmployeeClass(company, favLang) {
this.company = company;
this.favLang = favLang;
}
var emp1 = new EmployeeClass('XYZ Pvt Ltd', 'JavaScript');// Output : emp1
{
company: 'XYZ Pvt Ltd',
favLang: 'JavaScript'
}

Below is the current state of EmployeeClass prototype

EmployeeClass
|--Execution Code
|--prototype Object
|--constructor : fn() refers to EmployeeClass.
|--__proto__ : refers to global Object.prototype

Now its time to create a link between PersonClass and EmployeeClass so that, employee can re-use the Person properties & methods [name, age, walk ()].

How we do that here ??

EmployeeClass.prototype = Object.create(PersonClass.prototype);

This will change the prototype reference of EmployeeClass from default to PersonClass.prototype

EmployeeClass
|--Execution Code
|--prototype Object
|--__proto__ : refers to PersonClass.prototype
// Note : The constructor fn() is deleted from prototype object.

That’s it… We can create a new instance of EmployeeClass and try calling walk() from PersonClass on it.

var emp2 = new EmployeeClass('ABC Pvt Ltd', 'C++');// Output : emp2
{
company: 'ABC Pvt Ltd',
favLang: 'C++'
}
// Output : emp1.walk()
// Person undefined is walking

We were able to successfully call the walk fn() on emp2 object inherited from PersonClass. One minor glitch — we are getting name as undefined. Let’s fix that by modifying the EmployeeClass function.

Also, let’s add a new method code() on EmployeeClass to print the name and favLang of instated employee object.

function EmployeeClass(name, age, company, favLang) {
PersonClass.call(this, name, age);
this.company = company;
this.favLang = favLang;
}
EmployeeClass.prototype.code = function() {
console.log('Employee ' + this.name + 'is coding in ' + this.favLang);
}
var emp4 = new EmployeeClass('Mike', 30, 'MNP Pvt Ltd', 'JavaScript');// Output : emp4
{
name: 'Mike',
age: 30,

company: 'XYZ Pvt Ltd',
favLang: 'JavaScript'
}
// Output : emp4.walk()
// Person Mike is walking
// Output : emp4.code()
// Employee Mike is coding in JavaScript

Here, PersonClass.call(this, name, age) is basically passing the newly created object [referred by emp4] to PersonClass which interns populating name and age value on top of it and getting printed as output.

Further we can check whether the created Employee object is instance of EmployeeClass and PersonClass. 🏆

emp4 instanceof EmployeeClass // true
emp4 instanceof PersonClass // true
person1 instanceof EmployeeClass // false
person1 instanceof PersonClass // true

Conclusion 🎯

Please refer the top diagram “JavaScript [[Prototypal]] Inheritance — Code Flow & Prototype Linkage” and relate the below points.

1. All Objects in JavaScript have __ptoto__ which refers to global Object.prototype property unless created using Object.create(null).

var obj1 = {}
obj1.__proto__ === Object.prototype // true
var obj2 = new Object()
obj2.__proto__ === Object.prototype // true
var obj3 = Object.create(null)
obj3.__proto__ === Object.prototype // false

2. All functions [custom function foo or predefined/native String, Boolean, Array, Number] have prototype object property.
Again, as an object, __proto__ will be part of it which by default refers to the global Object.prototype property.
Also, constructor fn() on prototype refers to the function itself.

function foo() {/*some execution code*/}
foo.prototype.__proto__ === Object.prototype // true
foo.prototype.constructor === foo // true

3. Global Object.prototype refers to an object which has utility methods [toString, valueOf] etc.

4. Function as a constructor call is used to create an object using new keyword.

var childObj = new ChildClass();

5. The created object [[Prototype]] i.e. __proto__ refers to the created function.prototype object.

childObj.__proto__ === ChildClass.prototype      // true

6. To inherit properties from other Class [Function as constructor], we point the Child function dot prototype to Parent function dot Prototype using Object.create.

ChildClass.prototype = Object.create(ParentClass.prototype);

7. Further the Object created from Child function will also point to the Parent Function dot prototype and can utilize the Parent properties and methods.

childObj.parentClassMethod();   // Will workchildObj.parentClassProperty;   // Will work

8. Basically JavaScript engine looks for the property/method on the current object and if Not Found — it searches on the Parent Object and then the Grand Parent till it reaches global Object.prototype.
This is called Prototype Chain in JavaScript and termed as Prototypal Inheritance. 🍕🍕🍹

Hopefully this article was able to give you clear context on the differences between Classical vs Prototypal inheritance and implementing the Class-Object hierarchy in JavaScript using Function as constructor.

Further you can explore more on the challenges & caveats of different implementations techniques for prototypal inheritance.

Please put your thoughts, feedback or queries in the comment section and we can discuss further on that. ✌🏻👋🏼

--

--