In this article, we’re going to learn about Prototypes in JavaScript, especially about the Prototype Chain, how it works, when should we use it and its benefits. We’re going to learn how Prototypes allow JavaScript to achieve the concept of Object-Oriented Programming, and what that means.
If you’ve been using JavaScript for a while, you must have heard somewhere that “everything in JavaScript is an object.” Well, that’s not quite true!
We know for a fact that, in JavaScript, we can declare an object in two simple ways. We declare an object by using the declarative form:
const user = {
name: "Leonardo",
age: 22
};
Or, we can declare an object by using the deconstructed form:
const user = new Object();
user.name = "Leonardo";
user.age = 22;
By using either form you’ll achieve the same end goal, which creates an object. Although, it’s not very common to use the deconstructed form to create objects, because, using that form, you’ll end up having to create the properties of the object one by one.
We also know for a fact, that in JavaScript we have six primary types: string
, number
, boolean
, null
, undefined
and object
.
The null primary type is referred to as an object type, but it’s just because of a bug in the language, which causes typeof null
to return the string "object"
incorrectly (and confusingly).
The sentence that we discussed, that “in JavaScript everything is an object,” is not quite true. The truth is that except null
and undefined
, everything in JavaScript is derived from Object
.
In JavaScript, we have something that we call “object sub types”, which are some complex primitives. Functions in JavaScript are a type of “object sub-types” — they’re callable objects, said to be “first-class,” so with that they are basically just normal objects.
Also, we have something called “Built-in Objects” in JavaScript. You have most likely used them a lot before but may not have noticed. For example, if you want to create a string by using its built-in function, how would you do it?
const name = new String("Leonardo");
Now, if we use the typeof
on our name
, we’re going to see that it is an object.
typeof name;
// Result:
// "object"
We have the following built-in types in JavaScript: String
, Number
, Boolean
, Object
, Function
, Array
, Date
, RegExp
and Error
.
These “built-in types” are just like built-in functions: They can be used as a constructor — by using them with the new
operator — and the result will be a newly constructed object of the sub-type.
Now that we know a little bit about objects and built-in types in JavaScript, we can learn more about Prototypes and how they work under the hood.
We now know that almost everything in JavaScript is an object — besides functions that are an object sub-type and some primary types, the rest can be considered objects.
Prototypes in JavaScript are simply a special set of properties that an object holds, and each object in JavaScript holds its own set of prototype
properties. Since almost everything is an object in JavaScript, we can benefit from these special properties too.
So, for example, let’s imagine that we have an object called user
, like this:
const user = {
name: "Leonardo",
age: 22,
bio: "Full Stack Developer"
};
Now let’s imagine that we want to console the age
of our user
. We would do this:
console.log(user.age);
But, what if we didn’t have an age
property inside our user
? To determine if an object has a specific property, we can use the hasOwnProperty
method, which is a built-in method that we can call on an object to determine if there’s a specific property on this object.
console.log(user.hasOwnProperty("age"));
// Result:
// true
But where exactly did this hasOwnProperty
method come from? Well, every object in JavaScript receives its base behavior from another object, Object.prototype
. This Object.prototype
has a lot of common utilities that we can use all over our code, so that means that every object in JavaScript has it.
For example, you have probably frequently used the .toString()
built-in method, which is a method to turn anything to a string. If you try to use it in our user object, you’ll see that it won’t work well because you’re trying to turn a whole object to a string. Another built-in method that we use a lot in our code nowadays is the .valueOf()
, where we can check the value of a specific object or property.
The point here for you to understand is: every object in JavaScript has a special set of properties and methods that we can call anytime, because every object receives its base behavior from the Object.prototype
.
Since all objects in JavaScript have the prototype
property, if we use it the right way, we can mimic inheritance in Javascript. The prototype
is nothing more than a reference to another object and it’s used when JavaScript can’t find a specific property of an object that you’re looking for.
If you try to call a property on an object, JavaScript will go to the prototype
object and look for it, until it finds it. If it doesn’t find the specific property that you’re looking for, it’ll return undefined
for you. Otherwise, it’ll return the specific property. This is basically the Prototype Chain in JavaScript.
To see the Prototype Chain working in practice, let’s create an example. Let’s make an object called Person
which looks like this:
const Person = {
printName: function() {
return console.log(`Hello, my name is ${this.name}`);
}
};
This object’s simply going to have a function called printName
for now, which is going to print to us our name. Now, let’s create an instance for this object, called myUser
, which is going to look like this:
const myUser = Object.create(Person);
As you can see, we just created an empty object referencing the Person
object. Now, let’s give a name to it.
myUser.name = "Leonardo";
Something to notice here is that the string that we’re assigning to myUser
is not being assigned to the Person
object, just to myUser
. Assignments to objects never go to their prototype.
Now, let’s use the printName
function to print the name of our user.
myUser.printName();
// Result:
// Hello, my name is Leonardo
When we call the printName
property of our object, JavaScript will try to find the property. First, it’ll look inside the myUser
object, since we instantiated it from the Person
object. It won’t find anything, because the printName
is inside the Person
object. Then it’ll go to the Person
object and return to us the printName
. When we’re referring to this on the Person
, in our case, it’s referring to myUser
, the object that we instantiate from Person
.
To wrap your head around Prototypes and Prototype Chains in JavaScript, you must practice and read a lot about it. Since it’s been core to JavaScript since the beginning, a lot of developers are kind of skipping these concepts and don’t know exactly how they work, which is a mistake. This is very much related to Object-Oriented programming concepts, like inheritance, and, if you master these concepts and understand deeply how they work, it can help you not only in interview questions for your next career move, but also when you try to write more advanced code and libraries as well.
In this article, we learned about objects in JavaScript, that the old phrase “everything in JavaScript is an object” is not quite true, and finally about Prototypes and Prototype Chains. These are very important concepts to know, because they are core to JavaScript, and to Object-Oriented programming concepts.
Looking for more insights on JavaScript fundamentals? Check out JavaScript Fundamentals: Closures next.
Leonardo is a full-stack developer, working with everything React-related, and loves to write about React and GraphQL to help developers. He also created the 33 JavaScript Concepts.