I am going to talk about one of the Programming Paradigms, Object-Oriented Programming, but, more precisely, Prototypal Inheritance. If you are an intermediate JavaScript developer or want to learn further without much programming background knowledge, I hope this shot will be a good start for your programming journey.
First of all, have you heard of Object-Oriented Programming?
Object-oriented programming (OOP) is a programming paradigm based on the concept of “objects”, which can contain
and data in the form of fields (often known as attributes or properties) . code in the form of procedures (often known as methods)
However, unlike other OOP languages, JavaScript is not a class-based language (in ES2015, there is a new class
keyword, but, this is just a syntactical sugar), instead, it’s a prototype-based language. When we write codes in JavaScript, all the functions we create and the built-in methods and properties are intrinsically objects. Almost everything is an object, even null
is an object in JavaScript! The methods and the properties of all the built-in objects are created by prototypal inheritance “under the hood.”
There are many built-in objects in JavaScript, but I’d like to talk about the most common objects, Array.
However, before we do that, open a dev tool console and create an empty Array []
, then click the newly created Array instance. The instance is created by an array constructor function, which is a high-level global object.
Back to the console, you can see __proto__(called dunder, double under) proto
, which means that it is an instance created by a constructor function object, here Array
.c:
Remember! When you create a constructor function, the function name should start with a capital letter (just like native ones). This is a naming convention so, all other developers will know it instantly.
function Animal(type, name){
this.type = type;
this.name = name;
}
const myPet = new Animal('Dog', 'Milo');
A constructor object has a prototype property that contains its own constructor function (which is itself) and other method functions. Can you see all the methods of the global object Array
below ( concat
, entries
, filter
, map
, etc.)? All of these methods (functions) are linked to the Array
constructor object by the prototype object:
Whenever we create a new instance of a constructor function object, the instance is secretly linked to its constructor’s prototype. We call this a prototype chain
. The instance has a __proto__
property that tells us which constructor’s instance it is. Basically, Prototype Chain
is a mechanism to keep looking up a property until it finds one, starting from its own property and moving to the constructor, and then constructor’s constructor, and so on.
// Array.prototype.map
const arr = [1, 2, 3, 4, 5];
arr.map()
Like in the above example, Array (arr
) can use the map method thanks to the property chain. arr
is an instance of the Array constructor that is initialized by Array literal. I hope you have solidified the concept of the prototype chain, constructor functions, and instances.
Ok, take a deep breath. We’re finally going to start with Prototypal Inheritance.
If you look at the code above, you can see that this one has a few pitfalls as the codebase gets configurable and the constructor function could be used for multiple instances.
Now, imagine that you want to extend the methods of the Animal constructor to add some new features for all instances. You want to give an age property for each animal instance and you want to increment it individually. So, you write the code below:
Animal.age = 0;
Animal.getOlder = function(){
return this.age++;
}
In this way, we cannot leverage code reusability.
Since the Animal
constructor function only holds the getOlder
method and the age property, they cannot be inherited from the milo
instance I created previously. The property and the method are not linked to the instance; so, if you try to initialize the age property as you may expect (like milo.age = 0
), it will say undefined
. Eventually, you will have to create the individual property and method for each instance if you want to make it work.
Now, a couple of instances won’t be a pain, but what if you have hundreds of them? Can you imagine how many repetitive codes you would have to write and the amount of work you would have to take care of?
This is where the power of prototypal inheritance comes into play. It helps us save memory and keep codes
Since JavaScript is a multi-paradigm language, this is just one of the techniques used in order to write the codes in a more efficient way with prototypal delegation
. Each constructor is just an inherent object and its properties and methods(functions) can be linked and shared by the prototype
object throughout all the instances inherited from it.
I strongly recommend that you actually engage in coding while reading this.
Thank you for reading! I will be writing more content for beginners/intermediates who want to learn concepts in-depth!
Free Resources