- [Instructor] Using a prototype
can reduce the memory footprint of an app
when you're creating a number of objects
using a constructor function.
But you may still experience some duplication in your code
if you have multiple constructor functions
that share properties and/or methods.
To further optimize your code,
JavaScript allows you to base one prototype on another,
inheriting keys and values from another prototype
rather than creating and storing unique copies
for each separate prototype.
Building relationships between prototypes in this way
is known as chaining or inheritance.
The resulting set of relationships
between different prototypes is known as a prototype chain.
In the Hansel & Petal code for instance,
we're working with four separate constructors
each with its own prototype for arrangements,
live plants, bouquets, and flower stems.
Each of these prototypes includes the type property
with a value of floral.
And each of these prototypes also includes a log item method
with identical code.
So right off the bat, we could eliminate the duplication
among all of these constructors
by basing them on the same prototype.
But if we look closer,
we also find that some of our prototypes
share properties and values
that are not shared with all prototypes.
In fact, we can build out a set of chained prototypes
in which some are based on others
without all of them sharing the same properties.
Before we dig in, it can be useful to sketch out
the structure and relationships between our constructors
to determine just what our prototype chain should look like.
All of our constructors share a type property
and a log item method.
So we can create a generic item prototype
that serves as the origin of our prototype chain.
And then our existing constructors
fall into three distinct categories
based on their shared values.
Flower is unique, as is live,
but arrangement and bouquet both have the pot
and storage properties and values in common.
So we can create a parent constructor for cut items
and then chain the arrangement
and bouquet constructors to that.
So let's code this up.
So first off, before the arrangement constructor,
I'm going to create a new constructor called Item
and that's just going to be an empty function.
We don't want it to actually customize anything.
We just want to actually work with its prototype.
And so I'm going to go down here to arrangement
and copy the prototype statement for the type property,
paste that up here and change arrangement to item.
So we are customizing the prototype of the item constructor
with the type value of floral,
and I'm going to do the same thing with the log item method,
changing arrangement to item.
So now we have a generic item constructor
whose prototype includes values for the type property
and log item method.
And so now if we chain
all the rest of our constructors to item,
we don't have to duplicate either of those key value pairs
in any of our other constructors.
So then we've identified these three categories
and because arrangement and bouquet
both share some common properties,
I'm going to cut and paste arrangement
and move it down to the bottom
right before the end of our file.
And so I'm going to do the same thing with bouquet
and move that down here after arrangement.
And so now we have the live constructor
and the flower constructor
right after the item constructor
and its prototype information.
And so for the live constructor, first off,
we're not going to make any changes to the constructor itself,
but down here in our prototype statements,
we are specifying the type value
and we're specifying the log item value.
And instead of doing those,
we can just inherit those from the item constructor.
And to do that, I'm going to create a new statement,
live.prototype
equals new item.
And so this specifies item
as the parent in the prototype chain,
meaning that live is going to inherit its prototype
from the item constructor.
And because that item prototype
already has floral and log item,
we don't need to specify those again for the live prototype,
so I can delete the type statement for live
as well as the log item statement.
And so we've dried out our code here
by ensuring that the type property and the log item method
occurred just once in our code base.
And so we can do the same thing
with the flower constructor here.
So again, we're going to leave the constructor as it is,
but down here we are specifying the log item function again
for the flower prototype.
And instead of doing that,
I can simply specify flower.prototype
equals new item.
And then flower's going to inherit that log item function.
It's also going to inherit the type property
which I neglected to include,
but it should be included as a property of flower.
So that also is ensuring that properties that we intend
to apply to all of the objects
actually are rolled out to all of the objects.
So that actually, in this case, creating a prototype chain
helped us identify a hole in our code.
So I can take out the log item method from flower
because now that we have specified item
as the parent in the prototype chain,
we will automatically be inheriting the log item method,
as well as the type property from item.
Okay, so live and flower were the two constructors
that were unique in our prototype chain.
And now we come to arrangement and bouquet.
And so arrangement and bouquet
do also share the type property value floral
and the log item method, but between the two of them,
they also share a storage value of cool.
And so to dry out our code a little bit further,
we can create another intermediate link
in the prototype chain
that arrangement and bouquet will both descend from.
So before arrangement,
I'm going to create a function called cut
and it's going to be blank.
And so this is just going to be a constructor function.
And so cut is the category
that arrangement and bouquet both belong to.
They're both types of cut flowers.
And what's common to cut flowers
are things that we can actually specify
as part of the prototype.
So Cut.prototype.storage
equals cool.
And then what we also want to do
is specify that cut descends from item.
And so we'll say Cut.prototype equals new item.
And so cut is a slightly customized object
based on the item prototype.
And now that we have this object
with a storage value of cool,
we can specify that as the parent in the prototype chain
for both arrangement and bouquet.
So for arrangement,
I'm going to say arrangement.prototype equals new Cut,
so specifying cut as the parent in the prototype chain.
And now we can take out type because cut descends from item,
so we're getting that type and I can take out log item
because cut descends from type and we're getting log item.
And then I can also take out storage
and so arrangement now inherits
all of its non-customized properties from cut and item,
which are further up the prototype chain.
And likewise for bouquet,
we're going to specify bouquet's prototype
as a new instance of cut.
And then we are inheriting type from the parent of cut,
which is item.
We are inheriting log item also from item.
And we are inheriting storage from cut.
And then specific to bouquet is this flowers property
and that's going to stay
as a customization for bouquet itself.
And so we can save our work.
And I have my files being served from HTTP server
and have reloaded.
And so going to arrangements, we can test this all out.
I'm going to add an arrangement to the basket.
And again, I'm getting the custom properties,
name, base, quantity, and storage,
and I'm getting the inherited type and log item.
And over in live plants, I'll add one of those.
And the same thing, this works just like it did before,
where we have our custom properties
and our inherited properties.
And then over in build a bouquet,
we'll take six yellow calla lilies and an iris.
And we have our custom properties, including flowers.
We have inherited storage from the cut prototype
and we've inherited type and log item
from the item prototype.
And so again, we see that our code works
just like it did before,
but we have further optimized our code
and reduced duplication.