7 days of WordPress plugins, themes & templates - for free!* Unlimited asset downloads! Start 7-Day Free Trial

Next lesson playing in 5 seconds

Cancel
  • Overview
  • Transcript

4.2 Prototypal Inheritance

JavaScript is a prototypal language, and true JavaScript inheritance comes from manipulating an object's prototype chain. In this lesson, you'll learn about the prototype chain and how to implement prototypal inheritance.

4.2 Prototypal Inheritance

JavaScript is a prototypal language and that's relatively unique in the world of object oriented programming. But with that uniqueness comes a certain, shall we say, misunderstanding of how JavaScript works behind the scenes. And when it comes to inheritance that is doubly so. Because inheritance in JavaScript is based upon prototypes. We have what we call a prototype chain. And we get inheritance in JavaScript by manipulating this prototype chain. So we are first of all going to look at the prototype chain. And then we are going to look at how we can build our own. So let's start by creating just a simple object. It's not going to have any properties or methods, or at least that we define. And I'm just going to use the object literal. Now behind the scenes JavaScript is using the object constructor to create this object. So even though we didn't explicitly use the constructor. It is implied, because we used the literal. Now, every object in JavaScript has a very special property called underscore underscore proto underscore underscore. Now, first of all, whenever you see a property that looks like this. That has preceding and a suffix of underscores. That means that this is a very special property and you should leave it alone. Because it's named this way for a particular reason. It doesn't look normal. So the idea is if it doesn't look normal then I'm going to leave it alone. However in this case, this is a very important property. So we are going to look at it. And some of the older browsers didn't expose this property, but it was still there behind the scenes. We just couldn't have access to it. But all of the major browsers these days give us access to this property. And of this is a direct link to the prototype of the constructor that was used to create this object. So we can say that obj.proto is equal to object .prototype. Now object.prototype is the final link in the prototype chain. Every object that we create eventually is built from object prototype. That means objects that we create with object literal notation. That also means objects that we create by calling our own constructor functions. Now for example, here is a modified version of the person type that we've been using throughout this course. It has just one property and one method. I simplified it because this can be a complex topic. And if our code is simpler, well, then we are better off. So let's create a Person Object and let's just call it John. And we will pass John to the constructor. So now we have this John object. Let's look at its protoproperty. So this is going to actually point to Person.prototype. So a couple of lessons ago, whenever we first talked about defining our own constructor functions and putting methods on the prototype. We talked about identifier look up. And how JavaScript looks at first, the object itself, for the property that we want. If it doesn't find it, then it goes to the prototype of that object which is underscore underscore proto. So for example, John. greet is not defined on the john object itself. So JavaScript goes to the proto property and tries to find the greet method there. It finds it, so it returns it and then we get to use the greets property. Now, just a few moments ago I said that every object has a proto property, that includes other proto properties. So we can say John.proto.proto and this takes us to the next link in the prototype chain. Although in this case, that is object.prototype. Because, remember what I just said, every object is based upon Object.prototype. It is the final link in the chain. So let's go through the whole identifier look up again. If we try to use the greet method JavaScript is going to look on the John object. It's then going to hop to the prototype to find that greet method. It's gonna find it here, so it stops looking. It found what we wanted and it returns that. However, if we do John.toString. Well, we haven't defined a true string method both on the John object or on its prototype. So JavaScript is going to go to the next link in the prototype chain, which is the prototype of John's prototype which is object.prototype. And this is where it's going to find the toString method. And with every data type that we create and inherits, we essentially grow this prototype chain. So let's see what that would look like. Let's go to the person file. And we want to create a new type called Employee. So it's going to be a lot like what we did in the previous lesson except that we are going to use prototypal inheritance to do it. Now we have our first name in our position. But the first thing we want to do is create all of the properties of our person data type. Now we can do that manually, or we can use the person constructor function itself. And we can call that as if it were this employee object that we are building. We need to pass in the first name value, and if we had last name, we would pass that in as well. But since we only have first name, we will pass that in. This is going to take the this variable. It's going to call the person as this. And it's going to set up the first name property on this. So by the time this code executes, we will have this stuff. First name is equal to first name. I mean that's essentially what we are doing here. But of course the benefit of doing it this way is if we have multiple properties that we want to inherit then it's all done with one call. As opposed to doing so individually. So now we need to set up the position property. So we will just create that on this object, and there we have our employee constructor. Now as far as the greet method is concerned. We want the same functionality that we have but we want to concatenate the The employee's position. So we want to override the greet method. Now in the previous lesson we overwrote the greet method with parasitic inheritance. We have course saved the original greet method so that we could use that. But we replaced the greek method on the object. And we don't want to do that here. We want to keep the greet method on person.prototype to be the same. Well this really isn't an issue. Because prototypal inheritance just works. So we're going to override it. By defining a new greet method on employee. .prototype.greet, we will have our name parameter. And then we wanted the same functionality as Person.prototype.greet. So we will just call that method. We will say Person.prototype.greet, and we will use the call method for that function. We will pass in this. So that Person.prototype.greet executes as this object. And then we will pass a name. But then we want to concatenate the employees positions, so he will have our position. So that gives us the properties and it also gives us the method. However, we haven't actually set up the prototype chain yet. And that's where all of the magic takes place. So before we do that. Let's look at this, let's create var obs. And we want to create a new object that is going to have a basis of person the prototype. So basically what we want is Obs dots. Underscore underscore pro === Person.prototype and thankfully we have an easy way of doing that. It's a method called object.create. This will create a new object and we can pass in another object as the prototype of the newly created object. So we can pass Person.prototype and if we assign this to obj. This is going to give us exactly what we want. We will have a new object in obj, but its proto property is going to be equal to Person.prototype. But in our case, we don't want to just do that with obj. We want to set Employee's prototype to be that new object. So we say Employee.prototype = Object.create(Person.prototype). This will set up the prototype chain. So that's whenever we create an employee object, it essentially inherits from person. So let's go back to index. Let's get rid of all of these lines of code. So we have John as a person, and let's create Jim as an employee. So the name is Jim. Let's make Jim the manager. And we want to call the greet method on our Jim object. So let's do Jim dot Greet we will pass in Jane as the name. Now JavaScript is going to go through this process. It's going to look at the Jim object for greet. It's not going to find it, so it's going to look at proto. It's going to find it there because we defined greet on Employee.prototype. So therefore it finds it, It returns it and then it executes. And that's why we are overriding the greet method for a person. That is still intact. But because the employee prototype is before the person prototype, JavaScript finds this new greet method instead of the old Greet method. But now, let's say that we want to call the toString method. Well of course we haven't defined toString anywhere. So JavaScript goes through this process. It looks at Jim, doesn't find it, it goes to the prototype of Jim. Which is employee.prototype. It doesn't find it. It goes to the next prototype in the chain, which is person.prototype. Doesn't find it there. So then it goes to the next prototype, and that is object.prototype. And there it finds the toString method. So as you inherit one type from another, you add a new prototype to the prototype chain and that can decrease performance. Now notice that I didn't say it will always decrease performance, because it depends upon the property that you are using and where that property is defined. Like, for example whenever we call the greet method for an employee object. There's not much of a performance hit. Because JavaScript will search until it finds the greet method. And we defined greet on employee.prototype. So that will execute very fast. However, whenever we call the two string method. Well, we haven't defined two string anywhere. So JavaScript has to search multiple prototypes in the prototype chain, and that will decrease performance. Now don't get me wrong, it will still execute very quickly. But it won't be as fast as if we had defined two strings on employee.prototype. So the general rule of thumb is to have short prototype chains. However, once again, it just depends upon the properties that you are using. And where they are defined in the prototype chain.

Back to the top