“Colorful lines of code on a MacBook screen” by Caspar Rubin on Unsplash
Disclaimer: this is a slightly opinionated post. Feel free to disagree in comments :)
Overtime, this has become a standard question in interviews for a frontend/full stack role:
What is the difference between classical & prototypal inheritance in JS?
or it’s alter ego:
How do you do classical inheritance and how do you do prototypal inheritance in JS?
To answer the first, there is no difference. Conversely, classical & prototypal inheritance is the same thing. Or rather, we implement classical inheritance using prototype chaining or inheritance.
Second and the most important, inheritance inherently means copying of properties & behaviour. Here, by virtue of prototype chaining, it is merely delegation. Will explain further below.
Classical Inheritance
is where properties and behaviour are inherited from some map / blueprint.
Think of it like constructor functions mapping to another via prototype chaining.
Mind the following code block:
At this point, when we create a new object from Bar
it will get the properties attached to this
of Foo
like this:
const bar_object = new Bar();console.log(bar_object.name); // prints 'Hello'console.log(bar_object.age); // prints '31'
However, when we attach a new behaviour to Foo’s prototype, this is not available to bar_object
. As in,
Foo.prototype.sayName = function() {console.log('My name is '+this.name);}
Now if we do this:
bar_object.sayName(); // it throws an error
But ideally this should be available because we are attempting to perform inheritance and anything on the parent should be available to child. In this spirit, this is what we need to do make it work:
Mind Line 10. We are reassigning the prototype
property on Bar
function to another object.
According to MDN, this is what Object.create
does.
Essentially, it is creating a new object with it’s prototype set to the passed in argument, Foo.prototype
.
What this means is, going forward, all objects created out of Bar
using it as a constructor function will have access to the behaviour / methods we add to Foo.prototype
.
If we think of the Foo
& Bar
as classes with properties, they are basically blueprints of how objects created out of them should look like, similar to how we have classes and their instances in Java / Python.
Here, JS is made to behave like Java by coercing a prototype relationship.
What we did above is Classical Inheritance
using prototype chaining, and this is also called Prototypal Inheritance
as people think it is ok to add a qualifier like Classical
or Prototypal
to an age old term Inheritance
and think it is ok.
When we do this bar_object.sayName()
we are essentially invoking the method defined on Foo.prototype
and not our original constructor function Bar's
copied/inherited method.
However, the magic is not over yet. You see, the prototype also has a constructor
property that maps to the constructor function. It’s use case can be in objects created out of a function to know the constructor that created it.
However, we directly updated the prototype
property of the Bar
and as such, it’s constructor property will point to Foo
.
While we wouldn’t normally rely on the constructor property, it is still dirty code. So to clean up our act, we have to also modify the constructor property in Bar.prototype
. This is the complete code where inheritance happens from Foo
to Bar
.
There is however another school of thought where in it is said that prototypal inheritance
is basically an inheritance involving prototypes
or objects like this:
const foo = {name: 'John'};
const bar = {age: 21};
const foobar = {...foo,...bar,hotel: 'tango'};
This has been mentioned and explained beautifully here:
Master the JavaScript Interview: What’s the Difference Between Class & Prototypal Inheritance?_“Master the JavaScript Interview” is a series of posts designed to prepare candidates for common questions they are…_medium.com
To sum it up, next time some one asks you the classical / prototypal inheritance family of questions, tell them this:
You implement classical inheritance
using prototypal inheritance / chaining / delegation
. One cannot exist without the other.
Read up:
getify/You-Dont-Know-JS_You-Dont-Know-JS - A book series on JavaScript. @YDKJS on twitter._github.com
Thanks for reading.
Hit *clap* if you think this was worth your while :)
Find me on linkedin or revert back to me on comments.
I write about tech, mostly JavaScript: React, Redux, react app performance stories and frontend engineering.