And this is the recipe for inheritance.
That’s the standard. But why this? Why this… mess? And why does it work?
instanceof keyword, before closing with a look at future directions, a tool for exploring these concepts further, and my recommendations.
This is a big topic and we’re going to cover a lot of ground. Be sure to take advantage of the pause and rewind buttons in your video player. You can use the timestamps here to jump to sections of interest.
So, what is an object? Well, it is a set of name/value pairs. In other languages, you might call it a dictionary, or a hash, or maybe an associative array, but fundamentally, it’s key/value pairs. You can use any number of keys with any name, as long as it’s a string, and each string can be associated with any value. Those values can be of any type: any of our basic primitive types, as well as any object type, including functions, and of course, objects themselves.
An important thing to note about objects is that, although primitives are passed by value, objects are passed by reference. Let’s see what that means.
So if we have two variables, named
number2, and we assign a value to
number1—let’s say 3.14 etcetera—and then we copy that variable into
number2, those two values are not connected. So if we change
number1 is unaffected.
Objects, on the other hand, are stored by reference. What that means is that if you assign an object to one of these variables and then we copy that object into a new variable, we’re not copying the object. There’s still only one object. What we’re doing is copying the reference. The pointer. The arrow. So if we change
object1 gets changed as well.
object2.a is 42, but also,
object1.a is 42.
One last thing before we’re done with the basics.
If you ask for a property that isn’t found in an object, you’ll get
undefined as your result back. Now, you can assign
undefined to any property you want. That doesn’t actually delete the property. If for some reason you want to get the property out of the object entirely, you have to use the
delete keyword. Now honestly, in practice, the distinction is usually not that important.
Because functions are just regular objects, you can do everything with them that you can do with a normal object. You can assign properties to them; you can assign them to different variables; and when you do, they’re passed by reference, so you can run that function from its new location by just saying the variable name and parentheses.
When you put a function inside of an object, it’s typically called a “method.” You can run methods just like you run any other function by saying
object.methodname and then parentheses.
this keyword to the object that you used. So if you say
this will be set to
myObject. Then when the function returns,
this will be set back to whatever value it had before.
So, if we have
myMethod which returns
this.val, and we call
object1.get(), we’ll get a 42 back. If we call
this will be set to
object2 and we’ll get 3.14159 back. If we just call
this won’t be set to anything in particular. It could be undefined if we’re using strict mode; it could be the global object; it’s really hard to tell for sure.
So you have to be really careful when you’re using
this. If possible, I really recommend that use strict mode whenever you can because that will force
this to be undefined. It won’t prevent mistakes relating to
this, but it will help you catch them more quickly.
If you have a case where you need
this to be a particular value, you can force it by using either
bind(). Now the details of those functions are outside the scope of this episode, but let me show you an example of one of them.
If we say
myMethod.call(), then that will run the
myMethod function and force the
this value to whatever we said. So
myMethod.call(object1) will set
Okay, that’s the basics. Let’s get into some of the more complicated stuff.
It’s pretty rare that you’re going to be defining all of your object from scratch. You’ll typically have some sort of repeated pattern. For example, in this case,
object3 are all using the same function. And rather than define them all separately like that, which would be a maintenance nightmare in the long run, what you can do is use something called “prototypes.”
The way this works is that you can define a single object, and then have other objects inherit from it, or “extend” it. The way you do that is by calling
So if I have a parent object with a function and a value, I can create a new object (which I’ve called
child) by saying
Object.create(child). You can do anything with this child object that you do with any other object. You can add values to it or even extend it with another child.
Now the cool part is what happens when we start to use these objects.
The base object is just like before. Let’s say we say
this is going to be set to
get on that object. And when it finds it, it’ll call the function, which will say
parent. So that’s pretty normal.
But here’s the cool part. If we call
this is set to
child, but it won’t find it. So it will look at the prototype—it will go up the prototype chain—and look at
parent, and it will find
get there. When it finds that function, it will try to
return this.val, which means it will go back to
child, look for
val, and find it. So
child.get() will return 3.14 rather than 42, even though it’s using the function that was defined in
get on the grandchild. It won’t find it, so it will go up to the prototype and look for
child. It won’t find it there, so it will go to
parent, look for
get there, and find it. It will call the function, try to
return this.val, so again it will go back to
grandchild, look for
val. It won’t find it, so it will go up to
child, look for
val, find it there, and return 3.14159.
There’s one more wrinkle I want to share, and that is that every single object has a prototype, except for the base object, and any objects you create yourself to explicitly not have prototypes. Here’s what they look like.
By default, objects that you create have
Object.prototype as their prototype, and functions have
Function.prototype as their prototype. Notice that this is where those
bind() methods I was talking about earlier come from.
Now, this is way too much detail to show in most of these visualizations, so what I’m going to do is just use
[[Function]] to refer to those prototypes from here on out.
Once you have objects in a prototype chain, you might find that you want children to behave differently from their parent, even when the same method name is called. This is called “polymorphism.” Polymorphism means, “the same name, but different behaviors.” Now, technically, you can have polymorphism without inheritance, but we’re not going to get into that right now.
firmAnswer object that answered something differently—or answered in a different way—we’d just say
firmAnswer.get and assign the function. In this case, what we’re going to do is we’re going to return the same value and return “!!” at the end.
So if we say
answer.get(), that will give us “42” back, but if we say
firmAnswer.get(), that will say “42!!” back. Anyway, you get the idea.
This relationship is actually a little easier to see if we don’t have the function visualizations in there, so I’m going to stop showing them for now.
Now you’ll notice here that our
fn2 is looking at
this.val and our
fn1 is looking at
this.val. That’s a bit of duplicated logic. It’s not too bad here, but in more complicated programs, you find that that sort of logic is very difficult to maintain. So typically, what we’re going to want to do, is call
Unfortunately, that’s not quite as easy as it might seem. The obvious answer is to just call
fn1… to just say
answer.get(). That doesn’t work. It returns the wrong answer. It’s going to return 42. Do you know why? If you don’t, pause the video for a moment and see if you can figure it out.
Okay, here’s why.
When we call
this is set to
get property. It finds it and it runs
fn2. That runs
answer.get(), which is going to set
answer, and then look for the
get property on
answer. When it finds it, it will run
fn1 and try to
return this.val. But because
this is set to
answer, when it looks for
this.val, it will find it on the
answer object and return 42 rather than 3.14159, which is what we expect.
So, in order for this to work properly, we need to use the
call function. We need to say
answer.get.call(this). See if you can figure out why this would work.
Okay, here’s how it works.
When we call
this is set to
firmAnswer… it looks for
get… finds it… runs
fn2… and now it says
answer.get.call(this). That sets
this to, well, the same
this again. But then it runs
answer.get() directly, which tries to
return this.val, which looks for
firmAnswer, finds it, and returns the correct answer.
For example, we have this
answer object which, when you ask it to
get the value, returns the value that it has stored.
Well, it’s pretty typical to want to have multiple copies of this object, so typically what people will do is they will put the function in a prototype—which we’ll call
AnswerPrototype—and then they’ll have multiple objects extend that prototype to give us special values.
So we see here that
lifeAnswer has the value of 42, because it’s the answer to Life, the Universe, and Everything, and
dessertAnswer has the value of pi, for, well, obvious reasons.
If you want to specialize that answer, as we did with
firmAnswer before, you can do the same thing. We have our
FirmAnswerPrototype add its
fn2—the one that puts “!!” on the end—that extends
AnswerPrototype. And then we have our
magicAnswer extend that.
When you use this approach to organize your objects, the prototypes are typically called “classes,” and the objects—the objects that extend them—are typically called “instances.” A class that extends another class is called a “subclass.”
Creating an instance is called “instantiation,” and you’ll notice that there’s a two-step process for that. First, you create the object by extending the prototype, and then second, you initialize its data. (Remember, instances are usually about the data and the prototypes are about the methods—the classes are about the methods.) So we extend and then we initialize.
The problem with this is that this initialization logic is duplicated every time we create a new object. In this simple example, it’s not such as big deal, but in real programs, the initialization logic is usually pretty complicated. So we don’t want to duplicate it everywhere. That would be a big maintenance problem.
It also violates encapsulation. One of the nice things about object-oriented programming is that it allows you to decide how your data is going to be stored in a way that nobody else has to worry about. You just provide access to that data through your methods and then, if you want to change the way data is stored, then you just do it. You update your methods—your object’s methods—but you don’t have to update all the rest of the program.
But here, because all our instances are accessing
val directly, we can’t change the way
val is stored without having to change all of our instances.
So what’s really common is to use some sort of initialization function. In this case, I’m going to call it
constructor(). This is a common method that is used to initialize your objects.
Here’s how this works. Let’s say that we want to create a new instance for
magicAnswer. We’ll extend
FirmAnswerPrototype and then we’ll say
magicAnswer.constructor(3). That will set
magicAnswer and it will look for the
constructor property. It won’t find it on
magicAnswer, so it will look at the prototype. It won’t find it there, so it will look at the prototype of
FirmAnswerPrototype. It will find
constructor there and then run
fn0 is going to set
value. So it goes to
this, sets the value, and there we go.
Note that I’ve changed
AnswerPrototype without breaking any of the rest of our code: without changing the way
FirmAnswerPrototype has to be programmed or any of our instances.
Now, let’s look at the classical model. This is going to build on everything we’ve done up until now.
new is a little bit, well, weird. It doesn’t work the way we’ve seen up until now, and that’s what makes the classical model I’m about to show you different from the prototypal model I’ve been showing you up until now.
Now, before we get into that, I have to show something a little bit strange about functions. Remember that
prototype property I said I’d explain later? Well, I’m going to explain it now. And it is… it’s weird.
prototype properties. That
prototype property actually points to a whole ’nother new object with a
prototype object that’s just hanging out there.
I told you it was weird.
Now look at this closely. Does this look familiar?
Okay, so that’s a little weirdness of functions. Let’s see how this plays out to create the classical model.
First, let’s go back to our prototypal model. We’ll walk through it step by step.
So what we’re going to do is we’re going to create a class called
get function on our
AnswerPrototype and we’re going to create a couple of instances:
So that’s a basic example using the prototypal model. Now let’s do the exact same thing, but this time using the classical model and the
In the classical model, we define the constructor first. So we’ll create this
constructor property that points back to our
Answer function. That prototype is our class. It’s going to fulfill the exact same purpose that
AnswerPrototype fills in the top example. So we’ll set our
get method on
AnswerPrototype. Then we can instantiate it by calling
new Answer(). We’ll say
new Answer(42) and that gives us the right value. That’s going to create a child of
Answer.prototype and initialize it by calling the
Answer constructor with the value of 42.
The way it knows to create
prototype property of the constructor when you use the
The same thing happens with
That’s the classical model.
Now, it gets a little more complicated when we start dealing with subclasses. So let’s take a look at how this would work with a subclass. Let’s add the
FirmAnswer class that we looked at in our previous prototypal example.
Again, we’ll start out by creating a
FirmAnswer.prototype, but this one we can’t use because we need our
FirmAnswer.prototype to extend
Answer.prototype—and it doesn’t. So what we’ll do is, we’ll set
FirmAnswer.prototype to a new object that we’ll create by extending
Answer.prototype. That will cause the old
FirmAnswer.prototype to have nothing pointing to it, so it will get collected by the garbage collector.
Next, we’ll set the
constructor property to point back to
FirmAnswer. Now, as far as I can tell, this
All right, so we have
FirmAnswer.prototype with a constructor. Now we need to set our
get method on it. Then we can instantiate it as normal. we’ll say
new FirmAnswer(7). That will create our
FirmAnswer.prototype and we can do the same thing with
Here’s a side-by-side comparison of the two models. I’ve numbered each of the sections so they correspond. So number one in the prototypal model is doing the exact same thing as in the classical model. Go ahead and pause the video here if you’d like to study this further.
There’s one more detail I’d like to share with you.
instanceof. The way this works is it looks at the prototype of the constructor and compares it to the object. This is actually a little hard to understand unless you see it, so let me just show it to you.
We can ask if
lifeAnswer is an instance of
First, it looks at
prototype property. Then it looks at
lifeAnswer’s actual prototype. And if those two things are the same object then, yes, it’s an instance.
lifeAnswer wouldn’t be an instance of
FirmAnswer.prototype is over here.
lifeAnswer’s actual prototype is up here. They don’t match, so it’s not an
However, there is one caveat to this—one exception to the rule.
luckyAnswer is an instance of
Answer.prototype. Then it will look at
luckyAnswer’s prototype. That’s not a match, but it will go up the prototype chain and look at
Answer.prototype as well. That is a match, so
luckyAnswer is an instance of
class syntax, and I’ve got it shown here on the left.
Now, as far as I can tell in my research, that yields the exact same underlying object model that classical inheritance does, as I’ve shown here on the right. But it’s going to be much easier to work with.
If you want to see how that compares to the classical model, I have a side-by-side comparison here. Go ahead and pause the video if you want to study this in depth.
apply, for example…
It also is the one that’s most likely to have good IDE support if you want to do some sort of automatic syntax checking or refactoring in your IDE, and it’s also the only approach that supports
instanceof. You can hack in support for
instanceof into the prototypal model, but it’s not very convenient and actually ends up being uglier than the classical model.
"use strict";. Use the strict mode. It will help prevent situations where
this isn’t defined properly.
Third, use JSHint or some other linter. It will help you catch cases where you forgot to use
new or you used it in the wrong spot, as long as you use the convention where a class name starts with a capital letter.
Fourth, when the EcmaScript 6
class syntax becomes available, go ahead and use it. It might be a while: at the time I record this, it’s not available in any of the popular browsers, and that means it’s going to be a long time before it’s available in IE. But when it is available, go ahead and use it. It’s a nice, elegant syntax. It maps down to the regular classical model, which means it’ll play nice with all your existing stuff.
constructor property. What happens when you take it out? Can you find any case where it’s needed, or any case where it’s not needed?