Narrator: Let's now start to implement modules
that we talked about in the last lecture.
And for that, we're going to use the
extremely popular module pattern,
which is one of the most popular patterns in JavaScript.
And since we're now back to a big project,
you'll have these what you will learn topics
in the beginning of each video again
where I will list all the new things that you will learn
so you can reference these lectures later on.
So in this lecture, you're going to learn
what the module pattern is in JavaScript
and how to implement it and you will learn more about
private and public data, exposing methods,
encapsulation, and separation of concerns,
and how all data is related to the module pattern.
So this is going to be a really important lecture.
But let's first remember why we're gonna
use modules for a project.
And do you remember why?
The answer is that we create modules because
we want to keep pieces of code that are
related to one another together
inside of separate, independent, and organized units.
And in each of these modules, we'll have variables
and functions that are private, which means that
they are only accessible inside of the module.
We want it so that no other code can override our data.
So our data or code is going to be safe
and this is really important.
And beside private variables and methods, we're
also gonna have public methods, which means that
we expose them to the public so that other functions
or modules can access and use them.
And this is called data encapsulation.
So data encapsulation allows us to hide the
implementation details of a specific module
from the outside scope so that we only expose
a public interface which is sometimes called an API.
It is extremely important to have all of this in mind
when building complex applications.
So how do we actually create modules in JavaScript?
We use the module pattern, which is incredibly
powerful but at the same time incredibly
simple to implement.
All we need to know are the concepts of closures and IIFEs.
But we already know that, right?
So let's start with the module that handles our budget data.
And I'm going to call it budgetController.
So, budgetController.
And here is how we write the module with the module pattern.
This variable is going to be an immediately-invoked
function expression that will return an object.
So let's write that out.
So remember, an immediately-invoked function expression,
or IIFE, is simply an anonymous function
wrapped in parenthesis.
So just like this.
So, function.
And this is the function body, right?
And then we just invoke the function at the end
like this, and that's it.
And in here goes our code.
So let's simply put a variable here for now.
Let's say x is 23.
And just some simple function, let's say
you want the function to add two numbers.
So I'm going to call it add, simply.
And our parameter is just a.
And we return x + a.
So this is just a variable and a function
to show you how the module pattern works.
So you already know that an IIFE allows us to have
data privacy because it creates a new scope
that is not visible from the outside scope.
Right?
So our variable and our function, they are safe in here.
They cannot be accessed from the outside.
Now, the secret of the module pattern
is that it returns an object containing all of the functions
that we want to be public.
So the functions that we want to give
the outside scope access to.
So let's now test this out and return an object
containing a method here.
So, return, right?
And then an empty object, and all we need to do now
is to add a method.
And I'm going to call it publicTest.
And it will simply be a function that uses
our other function add so that
we can use it in the outside scope.
So we accept the parameter b.
But then we console.log the result
of calling the add function with b.
Okay?
Let's now quickly test this in the console, alright.
So this time I left the browser here on the other side
in full screen because we're going to need that
for this application.
So let's open up the console here, give it some space.
And let's start by testing that we can in fact
not access the x variable.
So we first need to reload this, of course.
So our budget controller, alright, so .x.
And it's undefined of course.
Because, as we know, from the outside
we do not have access to the inner scope.
And also using our add function does also not work.
So remember, this is our private add function.
So let's now prove that we cannot use it from the outside.
So let's say budgetController.add with five.
So five plus x.
And it doesn't work because it's not a function.
So this is what we expected.
And if we now go ahead and use our public test method,
so publicTest, and now use five,
then we have a result of 28.
So let's see why that is.
So we passed five here into the function
and then this five value is passed into the add function
and therefore the result will be five plus x
which is 23 which is then 28.
So using the public test method,
which is the one that we exposed to the public,
actually works while using the add methods,
or the x variable, does not because they are private.
Okay, so how does this work actually?
Let's analyze what happens here.
So when the JavaScript run time hits this line here
it gets executed and this anonymous function
is declared and immediately called or invoked
because of this operator here.
Then these variables here and functions are declared,
right, and we return an object right here.
And this object contains the method
that we called publicTest.
But it could of course be lots of methods,
not just this one.
So this object is what gets assigned to the
budget variable after this function returns.
So again, after all of this runs,
the budgetController variable is simply
an object containing the method called publicTest, right?
Because that's what we returned from this function here.
Okay? Now we saw in our example that this publicTest
method here then uses this add and this x variable
even after this function has already executed.
So why does this work and why is it so powerful?
And I'm sure that you already can guess why this works.
And so this works thanks to the power of closures.
So remember, because of closures, any other function
has always access to the variables and parameters
of its outer function even after
the outer function has returned.
And that's what happens here.
So the IIFE, the immediately-invoked function expression,
returns immediately and so it's effectively gone.
But the publicTest function that we return here
will always have access to the x variable and
the add function because a closure was created here.
That's why we say that the publicTest method is
public because it was returned and now we can use it.
But the x and add variables are private because
they are in the closure and therefore only
the publicTest method can access them.
So again, all of this works because of closures
to these functions and this x variable are in the closure.
Even after this IIFE here has returned.
So if you truly understood all the basics that
we talked about before, then this pattern is actually
quite simple but still very powerful at the same time.
And if you're not 100% sure that you
fully understand this concept, then you can always
review the lecture about closures.
Alright, so the first module is created
and we now understand how the module pattern works.
So let's create another module with just the
one that's gonna take care of our user interface.
And let's call that one the UIcontroller.
So we talked about this module in the last lecture, right?
So let's now create it.
So, User Interface Controller.
So again, we write an IIFE here, right?
So an anonymous function wrapped in parenthesis
which is then immediately executed or invoked.
So here we will write some code later,
and now we need our last module.
Now the two modules that we created
and by now are completely independent modules.
So there will not be any interaction
between these two ever.
Because I want them to be as stand alone,
as independent as possible.
So for example imagine that if you ever wanted
to create a more complex budget app
but a completely different User Interface,
you can take the budget controller module
and then expand it and not think about the
User Interface at all.
Because the User Interface is separated from the data,
they don't communicate at all.
And that is called separation of concerns.
And separation of concerns basically means
that each part of the application should only
be interested in doing one thing independently.
So again, these two controllers don't know about each other.
They are stand alone, they don't even know that
the other one exists.
Now we need some way to have these two connected, right?
For example, we need a way to read data
from the User Interface and then add
that data as a new expanse in the budgetController.
And that's why we create a third module
which is the app controller, and we also
saw that one in the last lecture.
So let's create that one as well.
So controller, simply, and now we already know
how this works, right?
Some space here, invoke the function, and that's it.
Now of course, modules can also receive arguments
because, remember, they are just function expressions.
And so we can pass arguments into them.
And that's what we're gonna do with this module.
We'll pass the other two modules as arguments
to the controller so that this controller knows
about the other two and can connect them.
So I will specify two parameters here.
Budget.Controller, and I'm going to write it
in a slightly different way.
And I will explain here in a second.
And a UICtrl. So these are the parameters.
And so now, when we call this function, we can pass
our arguments into the function.
And we want our created budget.Ctrl.
So this one here, we assigned to the budget.Ctrl,
which is this one here.
So inside of our function here of our
controller module it will have a different name.
And the same thing with the other controller.
So, UIController, okay?
So I could of course simply have used the
original controllers name inside of the add controller.
Or I could have even not passed anything into the
module and simply have used the other controls
in here in our function because of course we have
access to them because they are in the outer scope.
Right, so I could simply use the, let's say the
budgetController, like this, in here.
But that is not a good practice because this would make the
controller a little bit less independent.
Because imagine that we would change the name of the module
then we would have to do this all over our code.
We would have to change the name everywhere in here, right?
But we don't want that.
So this way, we don't have to do it.
So in case you want to change the name of
the budgetController to something else, we would
just have to change it down here.
And then set up the module so it will
always be called simply budgetCtrl.
So this controller now knows about the other two modules
and it can use their code.
So let's now actually try this out.
So we use our budgetCtrl and let's test the
publicTest method and pass again
the value of five into it, okay?
So let's now test this.
Then we store it in a variable, let's say z this time,
and now as you know we don't have x from the outside
to this variable so we have to create another method
simply to print this variable to the console.
So we need to return an object once again
and I'm going to create another public method.
So I'm just going to call it anotherPublic.
So these names don't really matter because all of this is
just to show you how these modules work,
and how they interact with one another.
So this is not gonna receive any argument
and now all we do is to console.log the z variable, okay?
Because again, doing it like this is the only way
that from the outside we can have access to z.
So let's now test this.
So, controller, and now we use another public method.
We call it and nothing happens.
And alright, I actually know why this happened.
Okay, and it's because in here we don't return
this value but we console log it.
And that's also the reason why this 28
appeared here in a console
and because, again, we did console.log right here
instead of returning it.
Okay so you will actually want to return
this result of the add function so that it
can get saved in the z variable.
So let's now test this again.
Alright, so this time we have nothing in the console
so far and now controller.anotherPublic.
And here we go. So, 28.
So we have already done a lot of stuff here.
We wrote different modules
both with private and public methods and variables.
And we also made them interact with one another.
So really cool stuff and really really important
concept that we learned in this lecture.
So what we just created is the bare bones
structure, or let's say architecture, over application.
And it's a simple one actually but it's perfectly
enough for this relatively small application.
And I hope that you see how important it is to follow
good architecture and I'm sure that you will see it
even more as you progress with the course.
A lot of courses will only teach you the coding part
but not the structuring and architecture
that are so fundamental for this kind of project.
Alright, so let's now start filling our newly created
modules with some actual code right in the next lecture.