Prototype-based Inheritance and Prototype chain in JavaScript (ES5)

In this article, we are going to deep dive into JavaScript prototype and understand how Object-Constructor relationship works

JavaScript is weird. If you are a seasoned JavaScript developer then you know that sometimes, it is completely different from other programming languages we are used to. For example, a function can be used as a mechanism to execute a piece of code in an isolated contextor a way to create objects. The weird thing is, in both the cases, function definition looks similar, it’s up to the compiler how it treats it.

In this article, we are going to focus exactly on creating objects by using functions. A function that is used, to create objects is called a constructor function. In JavaScript, almost everything is an object. Let’s understand it.

Almost everything is an

JavaScript has Primitive Data types and Reference Data types. number, string, boolean, symbol, null, and undefined are primitive data types. Primitive data type means when you create a variable, store a value of any given primitive data type in it, then declare another variable which is assigned (with the value) to the first variable, the second variable receives only a copy of the value from the first variable. Let’s see that in practice.

In the above example, we can see that variable name_max was assigned with variable name_john. Since the string is a primitive data type, name_max received only copy of the value from name_john. Later, we assigned a new value to name_max. This should change only the value stored in name_max and should not affect name_john in any way, which is proved here.

Reference data types work in different fashion. array, object and function are reference data types. When you create a variable A of reference data type (by assigning with a value of reference data type), the value is stored in the Heap and its memory reference is stored in the variable (this happens internally and _A_ is not a pointer). When you assign another variable B with the variable A such as B=A, instead of copying the value of A in the variable B, the variable B only gets the memory reference of the value A points.

But unlike other programming languages, if you assign a new value to the variable B, it won’t change the value of A. JavaScript will instead assign a new memory in the Heap and store the value there. Here, A and B are now referencing different values in the memory.

But instead of assigning a new value to B, if we are assigning a new value to the property of B, JavaScript will use the referenced object and modify the property-value on it. Since A is still pointing the same value in the memory, A will get affected here. Let’s see that in action.

In the above example, we created variables morning, mike & odd and then assigned a value of function, object and array. Later we created variables evening, john & even and assigned the given variables to them. Since, morning, mike & odd points to the value of referenced data types, evening, john & even will get only references to these values.

From the result, we can see that any changes made to the properties of the evening, john and even modifies the value they point. Hence morning, mike & odd are also modified. But in the case of kate, since we are replacing the entire value, JavaScript allocates new memory for the value and mike remains unaffected, as expected.

One weird thing you might have noticed in the above example is that we are adding a property info on the morning variable which is a function. We know that we can add properties on an object, because traditionally an object is a map of keys and values like {x:y,}. Then how this is possible?

In JavaScript, all referenced data types are objects, not in the traditional way though. Any variable which has **constructor** property on it, is an object. I will explain constructor in details later, but the important thing here to notice is that constructor is like a function from which the object was created. If x.constructor syntax returns a function, then x is an object.

Not only that, all primitive data types except null and undefined are objects. A string is generated from String constructor, a number is generated from Number constructor, a boolean is generated from Boolean constructor and symbol is generated from Symbol constructor. Whenever we use literal syntax, JavaScript uses constructor functions behind the scene.

⚠️ As I said null is not an object but if you try typeof null, it returns "object" which is not true. This is a noted JavaScript bug since the initial version of JavaScript. undefined however is type of undefined.

Constructor Function

Since we understood how almost everything in JavaScript is an object, it’s time to understand how to create an object from constructor function. Let’s first understand what a constructor function is.

A constructor function is like a normal function but it is invoked with **new** keyword. We can pass arguments into it or use it as a first-class citizen. this in a constructor function plays a vital role in object creation. this inside a normal function call points to the execution context.

this in a constructor function is the object it is going to create. Hence by modifying this, we can add/remote properties on the object. Let’s see a simple demo in which we will create a very simple object.

In the above example, we created a function name Animal. In JavaScript like other programming languages, we use constructor name with the first letter being uppercase, to look more like a class. Since we intend to use the Animal function as a constructor function, this inside the function will point to the object which will be created in the future. So, when the function execution starts, imagine this is an empty object {}.

Then we added a property name to the object with the value received from the arguments. We also added a property getName which is a function. This function returns a string and has access to the object in this object. To understand this in a normal function call,

After when we are done with our constructor function, we can speculate that what would be the object returned when it is invoked with new keyword and proper arguments. As seen from the console output, we can see that object contains name, getName properties. name the property has “Dog” value and getName is a function. When we call a.getName(), this inside getName function points to a and this.name becomes a.name.

Object’s constructor

In the above program, there is one more property constructor on the object (this should be hidden but codesandbox shows it). Earlier, we discussed that any variable having this property (hidden or visible) is an object. Since, a has it, it’s definitely an object. But what is it?

An object keeps the reference to the function constructor from which it was created inside constructor property. In the previous program, we checked if the value of constrcutor is equal to Animal and it returned true. Since, it is purely a reference, you should never override this property.

constructor property is not actually on the object a but on its prototype. Let’s discuss prototype so that you will understand what it is and how it works.

Prototype

A prototype is a kind of object which functions always have. This is saved inside the hidden prototype property of a function. This isn’t much useful when we are using a function as a normal function to do or return something but it’s very useful when a function is used as a constructor.

In the previous example, let’s see what our Animal prototype looks like.

As we can see, our Animal prototype is empty.

Let’s take a look at Animal constructor again. We have a property name which can be different because we are receiving name as an argument. Hence, every object created by Animal constructor can have a different name and we understand that. But do we really need getName function on every object? Can’t object reference a function with key getName. This function might be stored somewhere in the memory and object just reference it. This way, we can save so much space and object doesn’t have to carry so many functions with it which increases its size.

This is where prototype comes into the picture. A prototype is an object associated with a constructor function. This object is like any other object containing keys and values. Here values can be a function or anything else you want. When we create an object using a constructor function, the object carries a reference to this prototype as it carries a reference to the constructor function as we saw earlier.

proto property

As I said, the object carries a reference to the prototype object of constructor function, it saves this reference in __proto__ property. When you access a property of an object, object first looks at its own and tries to search property there. If it finds the property, it returns that, end of discussion. But if it fails to find the property, it looks at the __proto__ object which points to the prototype of the constructor function and tries to find property there.

Earlier I explained, if a variable has constructor property, it is an object. This constructor property lives on prototype which proto points. Hence, we can access it from the object. Now we know that how we can move getName function to the prototype.

From the above example, we moved getName function to the Animal prototype. We also added a static property (static because it never changes) generation to the Animal prototype. Then we created an object a from Animal constructor. By looking at Animal constructor function, we can say that object should have only name property and we can confirm that by looking at a object in the console.

If we check Animal prototype using Animal.prototype, we can see getName and generation properties. Since object a was constructed from Animal, as per our discussion, it should have __proto__ property exactly like Animal.prototype which we can verify visually. But how do we know a.__proto__ actually references Animal.prototype. This can be validated by using strict equal comparison which returned true.

⚠️ As I said null is not an object but if you try typeof null, it returns "object" which is not true. This is a noted JavaScript bug since the initial version of JavaScript. undefined however is type of undefined.
Since, getName and generation properties are on the prototype, we can safely access them on object a. When we do a.getName or a.generation, JavaScript first look for properties on a, if not found then on a.__proto__ which is equal to Animal.prototype (tip: which is also equal to _a.constructor.prototype_).
⚠️ As I said null is not an object but if you try typeof null, it returns "object" which is not true. This is a noted JavaScript bug since the initial version of JavaScript. undefined however is type of undefined.### Prototype chain and Inheritance

As we know that every constructor function has a prototype object. Initially, it is empty but we can add more properties to it as we desire. And every object has access to it from __proto__ property.

If every object has __proto__ property, then since prototype is also an object then it must also have a constructor and __proto__ property. Let’s see how it looks like on our Animal constructor.

As we can see from the above result, constructor of a constructor function’s prototype is the constructor function itself. It also has __proto__ object which points to the prototype of Object. Let’s see a magic trick.

In the above example, we added generation property on the prototype and accessed it using a.generation which works fine. But JavaScript also gives us a functional property hasOwnProperty on the object a which is used to check if the object a has a property on it or its prototype. It returns true if property passed to it is on the object a else return false if it is on its prototype or if it doesn’t exist at all. This is all fine but where the heck hasOwnProperty property came from? We never defined it on a or on Animal.prototype.

Prototype Chain

As we discussed, when a property doesn’t exist on the object, JavaScript tries to find it on the __proto__ object which points to its prototype constructor function. But since prototype also has __proto__ object which points the prototype of its constructor function, it tries to find there. This cycle continues until there is no __proto__ property on the prototype object.

Let me again bring you the earlier test.

As you can see, Animal.prototype was constructed from Object constructor function, Anima.prototype has __proto__ property which points to Object.prototype. And Object.prototype has hasOwnProperty method. So a.hasOwnProperty() call first tried to find hasOwnProperty property on a, then on Animal.prototype (through _a.__proto___), then on Object.prototype (through _Animal.prototype.__proto___). This is called as prototype chain. If you understood this, now you are close to understanding Inheritance in JavaScript based on prototype chain.

All objects in JavaScript travels back to Object’s prototype. Which means every object in JavaScript is created from Object constructor. Object constructor is generic and its prototype is not constructed from any constructor. Hence Object.prototype.__proto__ returns null.

Inheritance

In simple language, inheritance means properties you got from your ancestors. Your parents borrowed some properties from their parents and you borrowed some properties from your parents.

Let’s understand a simple analogy. All animals can breathe and see. But only dogs can bark and cats can meow. Hence, dogs and cats inherit breathing property from animal kingdom but they have their own bark and meow property. This can be applied to Object Oriented programming.

Let’s talk about actual implementation now. Animal constructor function can have breath property. Dog constructor function can have bark property. And Cat constructor function can have meow property. Both Cat and Dog inherit properties from Animal. This way, Dog and Cat constructor functions do not need to carry a huge burden of common properties and they can be shared through Animal.

⚠️ As I said null is not an object but if you try typeof null, it returns "object" which is not true. This is a noted JavaScript bug since the initial version of JavaScript. undefined however is type of undefined.
Then how can we achieve this? One solution would be to save Animal.prototype in Dog.prototype. This way can have all the methods defined in Animal prototype. But this is a wrong approach, let’s see.

In the above example, we created Animal constructor function and Dog constructor function. Then we added getClass prototype function to Animal. Then we assigned Dog.prototype with Animal.prototype hoping that all prototype properties of Animal will be saved inside Dog.prototype. Later, we changed Dog.prototype by adding a new method getName. By looking at the result, everything seems fine. But notice type of object d, it is showing Animal, this is weird because it should have been Dog. Then what happened?

As we discussed before, the prototype is an object and when you assign one object with another object, only it’s reference is copied. Hence, Dog.prototype is in reality is Animal.prototype. Hence, if we add any property to Dog.prototype, it will eventually end up on Animal prototype.

Also, since Dog.prototype is Animal.prototype and it contains constructor property which points to Animal constructor function, JavaScript console shows that object d is a type of Animal.

To avoid direct reference between these two prototypes, one might the copy (deep clone) Animal.prototype object and assign it to Dog.prototype. In that case, this won’t be an inheritance. We want Dog.prototype not to carry methods of Animal.prototype but only to reference them. This is where Object.create function is useful. Read more about it on MDN.

Object.create(prototype, {property:propertyDescriptor, ...}) is a syntax for Object.create function. This function returns an object, simple. This function accepts two arguments. The first prototype argument is the prototype which will be given to the object in __proto__ property (we know that). The second argument is an object which contains property names and their descriptors. This second argument is used to add extra properties to the object. If nothing is passed in the second argument, the object will be empty.

Using this function, we are going to create an empty object with Animal prototype and assign it to the Dog.prototype. We will leave the second argument null because we don’t want to add any properties on Dog.prototype yet. We will add them manually.

⚠️ As I said null is not an object but if you try typeof null, it returns "object" which is not true. This is a noted JavaScript bug since the initial version of JavaScript. undefined however is type of undefined.
Then we will add constructor property on Dog.prototype because it should be there for safety. Else, any object created from Dog.prototype will still say Animal because of prototype chain (you need to figure this one out, it’s simple).

From the above results, everything seems fine. Don’t hate me but this is still not inheritance. Since, Dog only inherited prototype of Animal, our object d is missing class property on it. Let’s expand the object d and have a look.

The object d is a type of Dog and contains only property name. Its prototype is a type of Animal because it’s the prototype of Dog.prototype. Dog.prototype has getName method and Animal.prototype has getClass method. We understood the prototype chain of d, so far, so good.

But in the case of inheritance, your object inherits all the properties of a parent. In this case, we missed the property. Some people might argue that class property should be on the prototype of Dog but that’s wrong. A prototype should inherit the prototype of the parent and constructor function should inherit the implementation of parent’s constructor function.

So think about it, what we can do that imports the underlying implementation of Animal constructor function inside Dog constructor function. Well, the short answer is, you cant. But there is a way. What we want is to execute Animal constructors code inside Dog constructor so that d get’s className property. We also should be able to pass the argument className.

If you have read my article on this operator, then you know this inside a function depends on the execution context. If you want to provide this manually, you can use functionName.call or functionName.apply methods. So, what we want to do is execute Animal function as a normal function from Dog function context. In nutshell, it’s like executing Animal constructor’s code inside Dog constructor. We will use call approach.

That’s it for the inheritance in JavaScript. I know this is a complicated subject but the way I explained, I hope it should have been relatively easy to understand. There is some extra information about the prototype.

  • We used Object.create to link Animal.prototype with Dog.prototype but you can also use Object.setPrototypeOf function. This is used to set or override the prototype of an object. Implementation is here.
  • You can use Object.freeze and Object.seal functions to protect an object, in our case that object is the prototype of a constructor function.
  • An object can have static metadata which is information associated with an object but not directly present on the object as object properties. You should follow the practice of adding metadata on the prototype.

Learn More

The Complete JavaScript Course 2019: Build Real Projects!

JavaScript Bootcamp - Build Real World Applications

JavaScript: Understanding the Weird Parts

#javascript #web-development

Prototype-based Inheritance and Prototype chain in JavaScript (ES5)
28.50 GEEK