字幕列表 影片播放
- I am here in this video
to talk to you about something called inheritance.
Inheritance in the context of object oriented programming
and JavaScript and ES6 classes.
Oof!
So, first of all,
there are three core foundational principles
to object oriented programming.
Let me write those down!
There's this idea of encapsulation,
there is this idea of inheritance,
that is the topic of this particular video,
and there is also the concept of polymorphism
which I will come back to.
And I have made videos on all of these topics before.
I can link to them.
Those videos, however,
were all made in the processing programming environment
and looking at these three principles
in the Java programming language.
Now I am talking about exactly the same thing
but in JavaScript.
And I have already made a whole set of videos about
encapsulation and object orineted programming in JavaScript
making use of something called ES6 classes.
So one of the things you have to get used to
if you choose to spend you life programming in JavaScript
is that it's just always changing
and there's 500 different ways to do the same thing
and everybody's got their opinion on which way is best.
And a lot of my older videos used a prototype
a prototypical object based way
of doing object oriented programming
with a constructor function
and you'll find those in older coding challenges
and you'll even find a set of videos about
how to do object oriented programming that way
and even one about how to do inheritance that way.
And if you watch that you're a true champion
because this is wildly confusing
and I have no idea if I explain that well.
But I am here in this video
to talk about ES6 classes.
So what is a class?
Oh, sorry, ES6 being the version of JavaScript
that came out in 2015.
It is currently 2019 while I'm recording this.
But it is now pretty widely supported across all browsers.
So, the idea of a class,
and I'm going to use as my example
something called particle,
because I am demonstrating this in the context
of animation and graphics.
So I'm drawing particles in a canvas
those particles move around the canvas
and the class is a template
for the making of an object.
If I create a particle class,
then I can have a variable somewhere else,
maybe I call it p,
and I can say new particle.
An analogy that's often used to describe
the distinction between the class and the object
is the cookie cutter versus the cookie.
So the cookie cutter isn't actually a cookie.
It's a thing that you can make cookies with.
So this is a template, there's no particle object here.
This is just a template to make actual particle objects.
And if I have my template
I can make more than one particle object
each with its own set of properites
all made from the same template.
So the new key word here,
saying new particle means execute something inside the class
called a constructor function.
So I'm kind of I guess by accident reviewing
some of the basics of ES6 classes
and object oriented programming
to get myself into the inheritance topic.
But I'm going to kind of move along
because you can find and see many more
details and examples about this in the other videos.
So this is the basic idea.
So let's go over to the code for a second.
So what I have over here is a canvas
with a little dot moving around.
And this dot is an example of a particle object.
So here's my class.
I have the constructor,
the object gets an x and a y
and the update function changes the x and y randomly
and the show function draws it as a boint.
A boint?
(laughs)
It would be great if there was a function called boint,
by the way.
Anyway.
So let's say now,
let's say this is your life,
this is what's happening to you.
You know what I would like?
I would like to put another one of these particles
I wanted to,
but I want it to look different.
And so I want it to be a square particle.
So the first thing you might do is like, okay,
I'm going to make a Boolean variable like isSquare
and I'm going to set that to a square,
I'm going to add another argument here square.
And then I'm going to say
alright, if this dot is square,
then draw this as a,
not a square a function,
then just use rectangle,
this dot x this dot y,
when will this ever end?
At least I could use the square function,
it's the least I could do.
Could say square,
otherwise make it a point,
and then, ugh, I'm so tired already.
I need a parenthesis here
and then I have to go over here,
and I could change this to like true
because I want it to be a square,
and then I refresh and look, it's a square,
and then I could say false and it's not.
So now I could have two particles,
oh, I could have p1 and p2
and I could have p1 do this
and p2 do this,
oh, I'm so tired.
This is so much work and so much coding.
And I'm going to call update and show on both of those.
And there we go.
Now I have my circle and my square.
Alright, so that's one solution to this.
I have two different mostly the same things
with some sort of core essential difference.
I don't like this solution.
Let me do it another way.
I'm going to make another,
I'm going to just create a new JavaScript file.
I'm going to call it square.js.
I'm going to go here,
I'm going to copy paste the whole thing
paste that in here,
I'm going to get rid of this idea of isSquare,
and I'm going to have a class called SquareP
for square particle.
I'm going to get rid of this variable.
And then I'm going to,
this one's the square so I'm going to draw it as a square.
And then this one is the circle
so I'm going to draw this just as a plain old point.
And I don't need this anymore,
and I don't need this.
So I have basically a particle class
and I have a square class, SquareP class,
they're entirely the same
but one draws as a square
and one draws as a particle.
Now I'm going to go back to Sketch.js
and I'm going to say new SquareP
and I'm going to refresh,
and if I did everything right,
no, SquareP is not defined
because I forgot to reference it
in my index.html so let me do that.
Then I'm going to go back
and there we go!
(bell dings)
Good night!
This video is now over,
but not at all!
In fact, I'm only just getting started.
All of this was exposition.
Exposition to the point where we are right now,
where we think to ourselves,
there has got to be a better way.
There has got to be a better way
than having some kind of type variable inside of my class
and then I use if statements,
or to have two separate classes
which I've just copy pasted the code
and changed some things.
How could I have this idea of classes
that inherit a bunch of properties from another class,
but modify them.
And this is in fact what inheritance is for.
So let's now think about that
in the context of this.
What if I could write another class
and I'm going to call that class SquareP,
which is like the silliest name for a class ever,
but it's somehow my example for this video.
This is what happens when you record a tutorial
after three hours of recording tutorials.
Class SquareP, ugh!
But I missed the most important piece of this.
You had to wait through so much video
just to get to this point
where now I am going to say extends,
and this is the most important thing,
particle.
This is the keyword.
Extends is a keyword in JavaScript.
In ES6 that makes the square particle class,
the SquareP class,
inherit from particle.
So let's think about what this is.
Now the constructor is a special case.
The constructor is a special case
where we're going to have to work with it in a different way.
But, if what this means
is if there is an update function,
update function,
and if there is a show function,
that it's as if I copy pasted
the update and the show function into SquareP
but I don't actually have to.
These functions are now part of the SquareP class.
It extends from particle,
it inherits particle.
This is also sometimes referred to as the child class,
or maybe the subclass.
And this is often referred to as the super class
or the parent class.
And the word super is quite important here
because that's actually a keyword in JavaScript
that's going to allow us to do some interesting things later.
In a moment.
Now while I could be done
by just inheriting update and show
and sort of assuming I'm also going to inherit the constructor,
it's a good habit,
and I think in almost all cases
you really need to explicitly write your own constructor
even if you are extending another class,
but in the case where all I want to do
is when I make a SquareP,
a square particle,
and actually in my Nature of Code book,
which this example is mostly the same,
I call this class confetti.
That's another name I could be using.
If I want to just say,
you know what?
I'm going to define my own constructor
but I want to do exactly the same thing
as whatever happens in here
and the way to do that
is just by calling the super function.
So the keyword super means
execute something from the parent or super class.
So super with parenthesis means run the constructor.
So let's now actually try to go over
and do this in the code.
So now what we can do
is we can say SquareP extends particle,
this is the magic.
Once I've extended particle,
I can just get rid of this.
That stuff is all inherited now from particle!
Woohoo!
And then I can just say hey, super, do the same thing.
And I still have to path in those arguments.
This is basically saying hey,
you're making a new SquareP.
When you make a new SquareP go ahead and make a,
call the particle code,
the code that's in the particle constructor.
So this is now the square particle,
let's call this confetti.
Just as a different name.
Now if I go back to the sketch.
And this was left over from before,
I forgot that I had this in there.
Right, if I run this again,
we have two identical particles.
It's as if I made two particles
because the confetti class,
the confetti object is a complete duplicate.
It just inherits the particle class completely.
But the whole point of this is we can now do things
like augment and override.
So what if I want my confetti object to always have a color?
So maybe I can add another value here.
Like I'm going to call this this.bright equals a random number
between 0 and 255.
So confetti objects do everything a particle does
but get an additional property.
And then maybe, you know,
I want to draw them a different way.
I want their physics to be exactly the same
so I want to inherit the update function,
but I want to draw them a different way.
So I can actually override the show function.
So if I write a function that has the same name
of the function that it's inheriting
then this will then be ignored for any confetti objects.
And just to change that name here.
Let me call this confetti.
So let's do that.
Let's augment and override.
I mean, those are sort of terms,
I don't know what the technical terms for those things are.
So back over here I might say something like
alright, so initialize x and y the same way
but add a new property
that's a random number between 0 and 255.
Then override the show function.
You know I could go back and be like,
how did I do this?
But I don't need to.
I don't even need to.
I'm just going to say in the show function I'm going to say
fill this.bright stroke 255,
strokeWeight 1,
and then I'm going to say square this.x this.y,
and oh, maybe this should also have
a variable called r for the side length.
And I'm going to make that 10.
And then I'm going to say this.r.
So now if I run this we can see, look!
There is a square, there's a confetti particle,
and a regular particle.
This is the idea of inheritance.
I can have a base class,
or I can have a parent class,
I can inherit from it,
I can add properties and I can override.
But guess what I could also do?
Let's say what I want to do is, you know,
my confetti object,
it should update just like a particle updates,
but I also want to do one thing more,
I want its size to change.
So if I come back to here one thing I could do
is in the confetti object I could say update
and then I could say well,
first do whatever you do in the parent object.
Call super.update.
So do whatever you would normally do for updating
and then do one more thing.
This.r plus equal random value.
So in addition to,
in addition to, sorry, changing the,
that's going to be too much.
In addition to changing the x and y
which presumably is taken care of by what it's inherited,
also change r.
And now, there we go.
You can see that this is now having an additional behavior.
The size is changing.
Now I don't know that the way that I've set this up
is particularly elegant or useful,
but what I will say is a common technique,
especially you'll see this in some of my videos
where I work with physics libraries,
is that you might have kind of this base class
that includes all of the code and math for the physics
of how something moves,
and you can imagine that being a particle class,
but you have all these different variations of that
with slightly different behaviors
and different design elements
so that base class can kind of be
the core physics of your system,
but lots of different things can exist in your system
and be customized in ways without having to duplicate code
over and over again.
I should also mention that classes can only inherit
from one other class,
but it is called a tree,
an inheritance tree because,
and an example I think I've given before in other videos
is an animal kingdom.
So you could imagine a scenario
where you have this idea of an animal class,
and maybe that has some properties that all animals share.
I don't know what this would be.
Weight?
That's all I can think of.
But then you might have,
from that you might have some mammal,
a mammal class, a reptile class,
those would have things specific to that.
And then maybe the mammal from that is going to inherit,
there's going to be a canine class.
I don't know if this is right biologically or what,
but the point is you can inherit things
all the way up the tree.
So if animal has a property called weight
and mammal has a property like fur color,
then canine is going to get fur color and weight,
it's going to inherit that.
Everything inherits.
So you can have,
it's not a network, it's a tree.
And so this is something that's really quite powerful
in designing large software systems
and working with other JavaScript libraries
that you want to have a very flexible and agile way
of augmenting and using features from something else
while implementing your own thing.
This is kind of the core principle
of object oriented programming.
Of inheritance.
So I need to come back and I need to do one more video
to talk about one other thing,
which is the term polymorphism.
Which for me feels a little less relevant in JavaScript,
because polymorphism really comes up
when you have a strongly typed language
cause how you specify what data types certain things are.
JavaScript is very good at just kind of
figuring it out in lots of cases.
But in this case what I can do
is I can make an array
that's full of lots of different kinds of objects
that inherit from each other
and then just blanket apply the same thing,
the same functions, the same functionality
to all of them.
So maybe I'll try to do one more video
just to basically take this and put it into an array.
Alright?
Thanks, I hope you got something from this.
There's probably like a lot more that you can do,
but this maybe gives you an inkling of how inheritance works
and might change the way you think about
making a project in JavaScript in the future.
Thanks!
(upbeat electronic music)
(bell dings)