Check out a free preview of the full Test Your JavaScript Knowledge course

The "Classes & Prototypes" Lesson is part of the full, Test Your JavaScript Knowledge course featured in this preview video. Here's what you'd learn in this lesson:

Lydia explains the concept of classes and prototypes in JavaScript. They demonstrate how classes can be extended and how properties and methods can be added to the prototype. They also discuss the difference between properties defined in the constructor and those added to the prototype. The lesson includes examples and explanations of how prototypes work and how they affect memory usage. The instructor also covers topics such as static methods and the use of object.create to create objects with specific prototypes.


Transcript from the "Classes & Prototypes" Lesson

>> Then we move on to classes and prototypes. Well, I'm sure you've used it in JavaScript, we can use classes and we can also extend classes. So in this case, we have an animal class and we can create a mammal, it's still an animal. So we still wanna have some of these properties in this case name.

All animals have names all mammals have names but mammals can breed unlike that's not all animals. Yeah, we have a canine, while canines, extends mammal cuz they can breathe, but then they can also howl. So wolves and dogs. And then we have dogs, which extends canine, but they can actually wag their tail, which I just learned yesterday that not all canines do.

It's just dogs and wolves, I guess. But anyway, we can make it more specific every time. Now, of course, when we create a class, there is something to remember is that's all the properties in constructor are specific to that instance, and everything not on the constructor is added to the prototype.

So in this case, we have a dog1 and dog2, and we create a new instance of dog. And we have name and breed on the constructor, so they all get added to that instance, so they all take up memory. We have name and breed, like Max and Labrador, and then we have Spot and Dalmatian.

But bark and wagTail are all defined on the prototype. So it's not directly on the instance, it goes down to prototype chain to find those methods. So if we were to invoke them, JavaScript would be like, well, I don't have the bark method on the instance. I'll go down the prototype chain, and then it finds it on Dog.prototype.

So as you can also imagine the methods that all instances would have in common we wanna add to the prototype cuz this doesn't take up memory. If bark and wagTail would be on the constructor, we would just have two identical functions, but each on an instance of this would all take up memory for no reason.

Yeah we can get the prototype of a specific instance with __proto__ this is deprecated cuz it can be a bit dangerous cuz you can also modify the prototype that way and you should not do that. Or you can use object that getPrototypeOf and then the instance to get the prototype just something to remember.

So then we already go to the first question with prototypes. Creating a new User instance would create a new login function in memory each time. Is that true or is that false? Well, the right answer to this is false. Also based on what I just explained, so we have the user.prototype.

And then we have a user1 and user2 instance. But the only properties on these instances is what's in the constructor, which is user name. Everything else will just be added to the prototype. So yeah, we won't be creating new or setting up new memory space, every time we create a new user instance, but we do for username of course, but that's just a string, that's fine.

We're not creating a new function in memory each time. All right, next one, which of the following statements are true? So we have a Dog class that in the constructor has a username and a wagTail function, and it also has a bark method up on the class body.

And then we have two instances, we have dog1 and dog2. And yeah, it's up to you to see which ones would be strictly equal to each other. So the right statements are A, C, D, and E. So what we have here is we have the dog prototype and then we have two instances, we have dog1 and dog2.

So first saying that dog1.wagtail = dog2.wagtail where we're strictly equaling the returned value of wagTail and that is just a string wagging tail and strings are strictly equal to each other. However, when we compare the actual function to each other, then they're not equal because we have the function on the constructor.

So they both point to different function objects in memory. And when strictly comparing objects, it's false, cuz we're comparing different references to different spots in memory. So that one's false. But in this case, it's also kind of stupid that we added it to the constructor cuz it's just a function we should have added it to the prototype.

But that's just what happens when you add it to the constructor. And comparing dog1.bark and dog2.bark while that is the same because they both point to the bark method on the dog prototype, so they both point to the same function objects are the same spot in memory, so that's true.

Object get prototype of dog1 and dog2 that's also true that both point to the same prototype. And dog1.constructor and dog2.constructor that is pointing to the constructor function on the prototype. And that actually gets called when we create a new instance. And when we say new dog, actually, that constructor function is called.

But yeah, we're just comparing the same function object to each other. So the same spot in memory so that one is true, yeah so in this case, don't add wagTail to your constructor doesn't make sense, it's not instance dependent. So they should have been on the prototype, just like bark.

Cool, there are no more questions we'll go to the next one. What gets logged? Is it 2 2, 2 3, 1 1, 3 2, or TypeError? So we have the Counter class, then we have increments, which increments this .count by one. We have a Counter(1) instance, and then we say that the initial count is 1.

We invoke the increments method. Then we have CounterTwo and we use object.create and just so you know with object.create we can create a new object that just has the prototype to the object that we passed as the argument. So in this case CounterTwo is an object with a prototype pointing to CounterOne.

But then on CounterTwo we also invoke the increment method. So, what gets logged when we log CounterOne.count and CounterTwo.count? So the right answer to this is 2 and 3. Let's see why, so, we have the Counter class which has the Counter prototype. And then first we say CounterOne with the initial value of Count as one.

Then we invoke the increment method on it, which that's kind of true. Then we create CounterTwo with Object.create, which just has the prototype pointing to CounterOne. But then we do something kind of tricky. And this is something also kind of tricky with prototypes in JavaScript cuz we increment this.count, we modified this.count.

However, when we modify something on a prototype in JavaScript and it doesn't have it on its own instance, it actually creates it on the instance itself. This is just something to remember cuz this, otherwise it should have been 3 3, but that's not the case. Because we modified something that was only available in the prototype, JavaScript will actually create that same property on the instance instead.

So in this case, it first created count 2, sorry about that count 2, because it didn't have it yet and we are referencing this account and modifying that value, so then it modified it to 3 but only on that instance. So, let me just show you this in the browser, can I do that?

I'm just not gonnq invoke this first counterTwo. Here you can see that counterTwo is nothing, it just has a reference to the prototype, Counter with count:2. But now when we do CounterTwo.increment, CounterTwo, you can see that it does have that count property. However, on the prototype, it's still 2.

And that was only the case because we cannot modify stuff in a prototype and JavaScript kind of does is to protect us. Cuz if we accidentally modify something on prototype and we have a lot of instances pointing to that prototype and we didn't know that we modified it, it would just replicate that modified behavior over all instances, and we don't want that.

So whenever we access something on a prototype, it's fine. Whenever we modify it, it will create the actual property on the instance to something to remember. And we did it because we incremented count by 1. So that's why it's three and two. All right, question 19, what gets logged?

We have a class again with a constructor color green, and then we have a static method, for changeColor. And this adds color to the new color and returns this a color, and then we have freddie, and he's green, and then we wanna change the color to orange. What gets logged?

Is it orange, purple, green, TypeError, or undefined? All right, so the answer to this is a TypeError because we're using static, and with static, all we're saying is that the method is only available on the actual class itself but not on the instance. That's just something you gotta know whenever you see a static keyword.

This is really just kind of if you wanna define it on the class itself maybe cloning it or creating it whenever we use this in. I don't know if you noticed, pass it to Chrome real quick. Yeah, well, typing code in Keynote is not the best. So we have it, Chameleon.changeColor.

Here you can see that it's that function, but if we do new Chameleon, it won't be there. We have color cuz i's on the constructor, but that's about it. So it's just, I don't know I think static is used for, yeah, if you wanna clone a certain class or change the behavior when it's created, stuff like that.

But that's what static is for. So it's not the same as private, private is that you can only use it within methods within the class, that's not what static is. We can also not use changeColor on a method in the class itself. It's just saying it's not on the instances, it's only on the class itself, which is chameleon and not a new chameleon instance.

So saying changeColor is an object, we're not doing anything, it's not a function, so it throws a TypeError. It's like what are you trying to do change colors? It's not a function, cuz changeColor is undefined cuz it's an instance and that there's a TypeError. Fun stuff, all right, last one for classes and prototypes which statements are true.

We have a class user with a username in the constructor and a login method on the prototype. Then we have the user instance. So yeah, it's up to you to see which are strictly equal to each other. All right, so the statements that are true is only A.

Let's see why. All right, so we have a user instance, for which the prototype points to the, a user shouldn't have wagTail, that should be. Yeah, wait one second, this should not have wagTail. This should be username John Doe. Not that it matters, I just want it to not be too bad, John, all right, well the rest will do.

So we have. The User class and this one has this is what I tried to say before, this one has an additional prototype property that points to that User prototype function and that one has the login and the constructor from that User class. So the User instance with username John Doe has a prototype that points to that User prototype.

The user itself is, or the prototype of User itself, points to function, or the basic function object. Because when we see class user I'm just gonna copy this in Chrome again, I just like Chrome more cuz you can expand things and you cannot do that in VS Code.

User., you can use all these methods, but where do they come from? Well, they come from the function constructor cuz we can do it's new function, or whatever. Cuz classes are essentially saying, or the function constructors that we used before, cuz we could also do function user something, and then you could have a function constructor the same way.

But then we introduce classes, but they still kind of have the same functionality as these function constructors that we use to use, prior to ESXi. So class User is inheriting a lot of methods or properties from this function, which on the prototype is null cuz it's kind of like the end of the prototype chain for function instances from there.

But then it has an additional actual prototype property, cuz it's a class that points to that User prototype. So it's not the same as like getPrototypeOf or __proto, that's different cuz user.__proto would point to function. Cuz it's a class which is essentially the same as a function constructor.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now