Transcripts
1. Introduction: We're on to a new section
and exciting topics. This section we will
deal with some topics that are really
central to JavaScript. All of these topics
are centered around functions and the
nature of functions. These concepts have led to
many of the patterns that have defined a high level of
development expertise. And it is important that
you understand and be able to apply what is in this
section in your own coding. We will first talk about the nature of functions
in JavaScript. The JavaScript function is very powerful because it is
a first-class citizen. And functions can be used
in higher-order ways. We will look at closure, a feature that I think is one of the most useful and
powerful features of the JavaScript language. We will deal with
immediately invoking functions and the
pattern around that. So we have a lot to cover. So let's get started.
2. Functions are First Class Citizens: Earlier in this course, I talked about how objects
are everywhere in JavaScript, with the exception
of primitives, everything else is an object. So as we discussed at that
time, functions are objects. The fact that functions are objects is such an
important feature. It leads to functions being first-class citizens
in JavaScript. Now, the idea that functions
are first-class simply means that functions are treated as values that can
be passed around. And since functions are objects, that is what makes
this possible. So when we think of a value, we normally think of something
like a string or a number. While any place a value like a string or a
number can be used. A function can be used also because they are
treated as values, which makes them first-class. To cement this idea, Let's look at several examples where traditional values can be used and show that a function can be used
in the same place. Now the first two examples
are pretty obvious. We can assign a value like
a number to a variable. Well, we can assign a function
to a variable as well. And we've done a lot of
times already at anytime we create a function expression
like is shown here. We are assigning that
function to a variable. That's pretty common. That's not strange
to us at this point. Now before I show
this second example, which is also a
pretty obvious one, I want to show something about functions here and how they're
assigned to the variable. We have fun ten. Now what if I were to
do something like this? What if I created
another variable? And it fun ten a and set
that equal to fund ten. So what's happening here? While, since functions are
objects, what it's doing, it's assigning a reference to this same function right here. Assigning another
reference to fund a. It is not invoking
the function and placing a ten in Fontan. Remember that's a
distinct difference. We have to use parentheses in
order to invoke a function. So let's just look at
this really quick. If we were to look at fun
ten a in the console, let me just open that up. We see that it's a function. That's what we're getting
displayed here as a function. However, if we were to invoke Fontan a by putting
prints after it, then we get the ten returned, which is what that function
is supposed to do. So important point about using the variable a
function is assigned to. If we don't put
parentheses after it, it will not invoke
that function. Alright, now, the second example
that we want to look at, I'm just going to
scroll it up here is a function can be assigned
to a property of an object. Now we've seen that
many times already. So that's why this one is
an obvious one as well. Basically const OBJ and set that equal to an
object like this. And then if we do
fun colon and then here's where we would put the function that's
assigned to that. And this one is just
going to log fun. Now, remember to invoke this, we use the dot syntax. We simply do OBJ dot and then whatever property it's assigned to in this case, fun. Once again, we use the
double prints to invoke it. Okay? Now this, as we've seen before, can be done with a
shortcut method like that. That would accomplish
the same thing, setting up a function there. And we get fun log
to the console. I'm going to close this just
a bit so we can set console. Alright, so that's
the second one. Those ones were
too obvious ones. So the third one, maybe not quite as obvious. And this one is a function
can be stored in an array. So let's set up an array here. And we're going to put
a number in there. A value can go into array, we already know that, but can we put a function
in there as well? Well, yes, we can.
And this time I'm going to do an arrow function. Basically it's just
going to return ten, like we've done in the past. So now we have a function in the second position
of this array. And we can invoke that
using the trends again. So we have to
indicate the position in the array like that. And then we just put friends
after that, we'll invoke it. So this should return ten. So if we log that
to the console, like that, we should
get ten on the console. And there we go. I commented
out this one up here, so attends the only thing
we're seeing up there. So a value can be stored in an array and a function
can be stored in an array. Now, a function can be part of an expression just
like a value is. Let's take a look at this one. I'm gonna do a simple
console log inside of there. I'm going to put an
expression so we can see the results
of that expression. Here's the expression. I'm just going to
do 30 plus what? Well, we're going
to do a function. So I'm going to declare
a function in here. And I'm going to
have it return ten. Now. Right now this
isn't going to add 30 plus ten because this
function is not invoked. We just declared it in here. So if we were to save this, let me comment out that
if we were to save this, it just concatenates the text of that function
to the number 30. However, if we were to invoke it and this is
immediately invoking it. And this is a topic we're
going to discuss in this section in
more detail later. But if I put double
prints right after that, now let's see what happens. Now. It invokes the function, returns a tan and
then adds 30 to ten. And so we put a function as
a part of an expression, just like we could
any other value. Now, to do the same thing, just so you're aware to do the same thing with
an arrow function, you would need to do
something like this, 30 plus. And then here's our
arrow function. And if we define that fat
arrow there of returning ten, that's great, except we can't immediately
put brands after that. We have to enclose
the entire thing in parentheses, like this. Then we can put
parentheses after it. Now we should get to console log statements at
40. And there we go. So that's how you would do
it with an arrow function. Now, the next example, we can pass values
into a function. A number can be passed
to a function of string, can be passed in the function. Well, so can functions be
passed into functions? So think callbacks. We've done a lot with callbacks. And that is an example
of where we're passing a function
into another function. So the most common example we've probably done in this
course is using setTimeout. So setTimeout has
two parameters. One is a function that we
pass in and the other is the amount of time
in milliseconds. So that would be 1 s there. This first parameter is
just a function we pass in. And I can do an arrow
function there for this one. And we'll just console dot log. Time is up, something like that. So here we're passing a
function into another function. So if we say this, we get the 240 is
a second later we get the time is up
displayed in the console. Now, the final example
we want to look at is a function can be
returned from a function. So down here at the bottom. So just like we can pass a
function into a function, we can return one as well. So let me set
something up, get fun. Set that equal. We're declaring a function here. And what are we going to return? What we're going to
return a function. I'm going to declare this here after the return statement, and we'll just have
a console log. Let's see, I was returned. How to do that? So that's our return statement. And what are we returning? Well, we could return a number, we can return a string, we can return a function because it is treated as a value. So now with this setup, if we go const new fund, we're going to store
the function in here that's returned
and set that equal to get fun and use the
prince to invoke it. Go ahead and save that. Here's our console
logs we have up there. But now let's see what
new fund contains. Now if I put new fun
here without the brands, will see the text
of that function. But if I do new fun with
brands and have it invoke, then we get the return value. We have the console
log statement, not the return value. So there we returning
a function. Now something we can do here. I've assigned the return
function to a variable, but I could also just call, get fun like this. And that's going to
return a function. Well, what if we wanted to invoke that function
that's returned? We can just enter another
set of plans right after it. So this first prints act
on the get fun function. The next set of brands act on this function that is returned and cause that
function to be invoked. So now, if we go
ahead and save this, we should see I was
returned on the console. And there's our
eye was returned. There's our setTimeout
console log statement. So there's a total of six examples of how we
can use a function, just like we would
use any other value, such as a number or a string, because a function in
JavaScript is treated as a value and that's
why it's first-class. That's why we call functions
in JavaScript first-class. Alright, now these last
two examples we looked at, we're going to delve
into more detail in the next topic when we talk
about higher-order functions.
3. Higher Order Functions: In the previous topic, we showed how functions in
JavaScript are treated as first-class because they're
treated like other values. In this topic, we're going
to expand on that idea as we talk about
higher-order functions. Higher-order functions
are simply functions that act on other functions by either taking them in as an argument or by
returning a function. We saw examples of that
in the previous topic. In fact, the last two examples showed higher-order functions. The fact that JavaScript
supports first-class functions makes it possible to create
higher-order functions. So the concept of first-class
functions explains how functions are treated in
JavaScript as values. The concept of
higher-order functions explains how we use them. Now here are those
last two examples we used in the previous topic. We have a set timeout and we're passing
in a function here. And we also have
another parameter which is the amount of time. So the fact that we can use a function as a
parameter and pass that in makes this function acting on the setTimeout function
acting on other functions. This is the one that's passed
in and it's acting on. And so because of that, it is a higher-order function. Down here. This
gets fun function. This one returns a function and because it's acting
on other functions, it is a higher-order function. So basically higher-order
functions either take functions as a parameter
or return them. So we understand what
higher-order functions are, but why are they so important? Now the most common
application of higher-order functions in
JavaScript is the callback. There are several methods in JavaScript that allow us to pass a function that will be used as part of that method or function. So it'll be called back. Anytime we create
an event listener, we're setting up a callback. And so they're pretty
common in JavaScript. Now I want to use setTimeout
function as an example and dissect why it is better as
a higher-order function, what makes it better? So I'm gonna go to a different code file now where I've got two setTimeout functions
already created. Now first, I want to focus
on the last parameter, which is the amount of milliseconds that
the setTimeout runs. So we're passing in data there. By passing in data to
this setTimeout function, it makes it more flexible. Instead of calling a
setTimeout function that always runs for 3 s, we can pass in the number of milliseconds
we want it to run. And it will run for that number. So by being able
to pass in data, it makes the function
more flexible. It also helps us help prevent
us from repeating code. If we had to have a
setTimeout function that ran for 3 s and
one that ran for 4 s. They're basically doing
very similar things, just a different amount of time. And so by being able to pass in data like
we've done here, we hold to that dry principal. Don't repeat yourself. Don't repeat code. We do that by passing
in a parameter. Well, the same thing can be said for passing in a function, for making a
higher-order function. The data that we pass in
controls its flexibility. By what data it can act on. The function we
passed in controls its flexibility by affecting
the functional aspect of it. So let's take these
two examples. I have a setTimeout that after a second is simply log
to the console logging. That's one example. I have a setTimeout down
here that after 2 s, it logs or it returns
two plus two. That's another example. Now, it's possible that in order to meet both of those
functional requirements, we could have created a setTimeout log
function that every time it was called a log
something to the console, we just passed in the
data that we wanted log. And we can create a setTimeout add function that every
time it was called, it would add some numbers
after the time expired. That would be two
separate functions. And we would be repeating code. But because setTimeout
is higher-order, we can pass in a function
that can do anything. So it's more flexible. Some may argue
it's more complex. And I think it is when
you first learn about it, when you first learned about
higher-order functions and understanding
how to use them. But once you're
familiar with them, it's really not that
much more difficult. It really isn't. And the flexibility
becomes very powerful. So that whole concept of dry, don't repeat yourself, is one of the reasons we want to have higher-order functions. Now, as I mentioned,
JavaScript is full of higher-order functions. Methods on many of the different types are
higher-order functions. E.g. arrays have several
methods that are higher-order. They accept a function
as a parameter and then does something using the function
that is passed in. But I just want to point
out and make you aware that higher-order functions are found all over in JavaScript. I think some people that are new to JavaScript or just
beginning in JavaScript, they avoid them because
they seem complex, but you can't avoid them. They are so powerful. Alright, let's move
on to the next topic.
4. Creating Your Own Higher Order Function: There are a lot of methods
in JavaScript that take advantage of
higher-order functions. They solve problems using patterns that take advantage of those higher-order functions. And we can learn from this
and use it in our own color. As just one example, let's look at this sort method that is available for arrays. Here I've got two arrays, one with names and
one with numbers, and we're going to sort them. So let's do the names and
also numbers like this. Then take a look at the results. So if we save that, let me get out here
to the console again. And now we look at those
two arrays, names and nums. We can see that with the names, things are sorted correctly. They're sorted in
alphabetical order. But what the sort method
does with numbers is it converts them to
a string and then sorts alphabetically
based on the string. And so we're getting
some really weird stuff here with numbers. And so sort by itself is
not ideal for numbers. However, the sort method was set up to take a
higher-order function, a compare function
as a parameter. We can pass a function
into the sort method. It will use that function to
do a comparison on elements. It will take each element
two at a time down through the array and compare them based upon the
function we pass in. And then that will
determine the sort order. Now, the way that works is if the first argument
that is passed in. So when we create our function, it passes in the
first two elements. If the first argument should appear before the
second argument, then we need to make
sure that our function returns a number less than zero. If the second argument
should come before the first argument than a number greater than zero, it
should be returned. Now, think about the
advantage of that. We're gonna do this
in just a minute. But think about
the advantage that this sort method is no longer limited to
just sorting strings. We can now have it
sort other things because it accepts a function
as one of its parameters. And it uses that function
and calls it for, in this case, the elements two at a time
as it passes them in. So let's try that with nums. So I'm going to
pass in a function. And like I said, that function needs to
accept two parameters. It's going to accept
the first two elements, and so on as it works
through that array. Now, since we need to return
a number less than zero, if the first argument
should become, should come before
the second argument, we can do something like this, returned a minus b. And this will do a sort order. Smallest to greatest. Week could reverse that
going the other direction. Because look, if 100 is passed in and 95 is passed
in for a and B, 100 -95 equals five. So that is a number that
is greater than zero. And that means that the second argument will come
before the first argument, so it'll put 95 before 100. Now, it's going to compare
all of those numbers together and get them in a sorted order sort
knows how to do that. All we have to do is pass in the function like
what we've done here. So if we save that and
take a look at nums again, we see that it's
smaller to greater. So numerous methods in JavaScript
take advantage of this. The ability to accept a function
and call it when needed. And we can do the same
thing in our code. We can take advantage
of it as well. Let's say I wanted to create a function that
processes strings. Let me just go ahead
and copy it in here and then we'll,
we'll talk about it. Here's my function that
processes strings. We allow a string
to be passed in, and then we convert that automatically convert
that uppercase. That's what we do in this
process string function. I'm trying to keep it
simple so we can keep this callback
information, the focus. So it'll convert
it to uppercase. However, if we send a
callback, it will do more. It will do whatever we
indicate with a function. So suddenly this function
is a lot more powerful. It can do a lot more. Now notice how we deal
with the callback. We create a new string
with two uppercase. But then we check to see if the type of callback
equals function. So if something has been passed
in and it is a function, then we go ahead and invoke it. And pass in this new string that we've already done,
the uppercase conversion. That callback does whatever
it needs to and returns it. And then we return that value. If there is no callback, we just return the new
string that we created. So this can give you an idea, a pattern for making functions that are a
lot more flexible, a lot more powerful. Now let's go ahead
and just try this. Let's just use it so we
can see how it works. Fine, I'm gonna
do a console log. So I want to log the
results of what is returned from processed string or from processed string
to the console. So I call process stream, that function right there. And I'm going to
pass in a string. So let's go ahead and
set up a string up here. Const STR one. I'll just set this equal to. This is a string, something simple like that. So we want to pass that in STR one to this process
stream function. Now we want to pass
in a callback. And I'm going to set up
that callback right here. So I enter function, it's gonna be
anonymous function. There's a curly brace now
I can define what it does. But one thing we need to do is we need to
make sure that we put a variable here for the parameter
I'm just going to call that vowel for value. Because look what's
happening up here. It's passing in that new stream to this callback functions. So we need to make
sure we accept it, accept it, and then
do something with it. Well, let's say all we
want to do more as just create an array
out of that string will split on the space. So we use the split method
and split on the space. So we will return that
once we've done that. Then here's the split method. And then we just put space in there as what we
want to split on. So what we should get, what should log
to the console is this string all in uppercase? Inside an array in each
word will be in its, be its own element in the array. And so we've made our
process stream function more powerful and more flexible
by making it higher-order. So let's go ahead and save
this and take a look at it. And there we get an array. Everything in
uppercase, each word, its own element in the array. So what I want you
to get out of this is the power of
higher-order functions. Higher-order functions are
used throughout JavaScript. We can also take advantage of that feature in our own code. And with this simple example, that is what we have done. Alright, let's move on
to the next section.
5. Exercise Start: Creating Higher Order Function: Throughout the course,
we've already seen a lot of examples of higher-order
functions when we talked about the
callback pattern. As I said, those are all
higher-order functions. We've just looked at a
few other examples in the last few topics. So I think it's time now to give an exercise where I have you create a
higher-order function. I think once you create
one on your own, it helps cement the power
of that whole idea, which I think is
important to cement, is something to remember
about JavaScript. That lens to JavaScript, one of the, one of the features that
makes it so powerful. Here's what I'd like you to do. I have a variable
declared your greeting, and then I'm calling a function. And notice I'm passing
in three parameters. One is a greeting, because this function is create greeting is going to
create agreeing for us, another as a name. And then the third
is a function. So what I'd like you
to do is to build the create greeting function and have it take
three parameters. If only two parameters provided, it simply returns a greeting. But if a third
parameter is provided, which is the function
before it returns that greeting by putting the
term and the name together, it should have that function
act on that greeting. So it should first
put these two pieces together and then check to see if the function exists
and have an act on it. And so create greeting is going to be a
higher-order function. It's going to give us a
little more flexibility. Not only are we able
to pass data in and have it returned
compiled greeting, we're also going to be able
to pass in a function that will have us do different
things with that greeting. Now this is a simple example, but it shows the pattern of a higher-order function
or the pattern of using a callback to make the function you create
more flexible to give it additional functionality so that you're not repeating yourself. Alright, go ahead
and give that a try. And then when
you're ready, go to the next topic and we'll
go through it together.
6. Exercise End: Creating Higher Order Function: Okay. How did you do with that? I'm gonna go ahead
and do it here. That gives you a
chance to compare what I have done with
what you have done. Maybe learn some
additional things as well. So up above, I'm going to go
ahead and set up Function, create, greeting.
Just like that. Now we want three parameters. I'm going to call
them turn Greeks and then fn for the function
that could be passed in. Alright. Now, I'm going
to declare variable, and this is gonna be
the initial greeting, just putting together those two, the term and the name. And it looks like
I didn't I don't know why I put greet there
instead of name. There we go. So it's gonna put term
and name together. And it's going to place
that in this variable. I'm going to use a
template string. So I use a back tick, and then I use the dollar sign and the
curly braces for a variable. The first variable
I want to include his term and then I want
a space between them. Then I'm going to include
the next variable, which is name like that. And so we've created our greeting and that
could be returned. If there's no function, then we would go
ahead and return it. So the way I'm gonna do this is I'm going to check to see if this value that's passed
in is equal to a function. If it is, we'll go ahead and run the function on it
and return results. Otherwise, I'll just
have a return statement after the if statement. If the if statement does not run than the return statement will run and return
this greeting. So let's look at how we do that. I'm going to just if then type of That's how we
find out if something is a function type of Fn triple equals and then
inside of quotes function. So if that is a function, this part of the code
is pretty simple. We simply want to return the
invoking of that function. But when we invoke it, we want to pass in greeting. Now let's see how that works. So a function gets passed in and it gets placed
in that variable. Since we can treat
functions as values, since the first-class, we can
store them in a variable. And so now that function is
contained that variable, we can then invoke it using parentheses and we pass in
a parameter right here. We can also check to see
if it's a function by using the type of and that should be a semicolon
there. So let me fix that. Says part really is
not that difficult. Sometimes more difficult
part is what you pass in, the functionality you pass in how you want to
accomplish something. Alright, let's go
ahead and finish this. So if this is not run, if this part here is not run, we still want to
return a greeting. And so on the very next line, I'm just going to put
return, greeting. And that way I can use this with a function or
without a function. It makes it all the
more flexible for me. Alright, so let's go
ahead and save that. And let's jump out
here and Sue are getting open the console here. And I declared a
greeting variable. Let's see what's in that now. Notice we have good
morning Anika. So that was the term in the
name of this passed in. And then these exclamation
points were what was added based
upon the function. I pass them, let me just
jump back to that call. So term, name and there's a function is going to take the greeting
and then it's going, Here's the template
string again. So it's going to take what has finished because that greeting
is passed in right here, is passed into it, so rich, it receives it in this variable. And then we use that variable in a template string with
exclamation points after it. Alright, so that's
working for us. Now, let me just do an example of create grading without
passing in a function. I'm going to go. Now I'll
just use my name here. And it still works because
we did that type of check. We do that if statement is still works if we don't
pass in a function. Now, just to show
the flexibility of this simple higher-order
function, let me do another one. I'm going to do a
different function here. I can type correctly here. And now for this
particular function, once again, we need a variable to accept a greeting
that's passed into it. Doing an arrow function again, and I'm just going to
convert it to uppercase. So something simple like that. So here's another example. Now if I press return, I get that syntax there. Can you see y? Notice I
missed the comma right there. So I'm gonna go back up and I'll just come back over here. So the message is
malformed, arrow function. The reason is malformed is because we didn't have
a comma separating. So once it got to it, it was considering this
a part of it as well. And so consider
that metal forms. So now if I press Return and
we get it all in uppercase, just shows an example
of what we can do with this now, very
flexible function. Alright, hopefully, that
was a good exercise for you in applying the whole idea
of higher-order functions. Alright, let's move on.
7. Closures: We have come to what
I think is one of the most important
concepts in JavaScript. Closure. You need to understand and use closure to be a serious
JavaScript developer. Now closure is
something that is not understood by new
JavaScript developers. I can remember when I first got the idea or understood
the idea of closure. It was an aha moment for me. And then I was able
to see it in lots of code and use it to solve
particular problems. So first I want to
look at a definition. This comes from Kyle Simpson. He states closure is
when a function is able to remember an
access its lexical scope, even when that
function is executing outside its lexical scope. Variables and functions from its lexical scope are still
accessible to a function, even if that lexical scope is not the currently
executing environment. Now those variables
and functions are held in memory because the JavaScript engine sees that there is still something
that can reference them. Now, when does this
type of thing happen? When is a function execute
outside its lexical scope? Well, it's really
quite frequent, but to know that and
to explain it better, we need to start looking
at some examples. The first example
I want to look at, I'm going to call this
function delayed greeting. And we're going to look
at how this works. And then I'm going
to explain what is going on and what
closure is happening. So we have a function
here that we're able to pass in a
parameter name. This is going to do
a greeting for us. We're going to declare two variables inside
of this function. One is the greeting. Good morning, we'll do
a space after that. And then I'm going to use one leaped to declare both of these. The other one is a pumped
variable for punctuation. And we're just going to set that to an exclamation
point. That's all. So there's our two variables. Now, all we're going to
add is a setTimeout. We've used this a
lot in the past, so this will be a great
way to illustrate closure. Settimeout is having a
function passed into it. As we know, that
function will not invoke until after the time is expired. And when the time is expired, if you remember, the function
is placed on the queue. And then once no other
JavaScript is executing, is then added to the
stack and is executed. Now here's what
we're going to log. We're just going to log
the Greek variable plus the name that's
passed in m plus. Alright, now let's go
ahead and set this to 5 s. Like that. Alright, now let me talk about
this in terms of closure before we actually watch it. And let me go ahead and do degree delayed viewing down
here so it'll invoke it. But in terms of closure, so we load this JavaScript
file and the function. And as we begin
executing the code, we encounter this, we
add a function to it. And then we encounter
this which invokes. That function is then
placed on the stack and it begins to work through
the code inside it, creates an execution context, context for this code. And so this variable and this variable
and this variable is all accessible by the
code inside the function. Well, it encounters
a set timeout and setTimeout is handled
by the browser as we know. And so the browser starts
counting down the 5 s. Well, that function
completes its done. Before this countdown
is finished. It is done and is
removed from the stack. So what happens to
these variables? Are they still accessible
by this function? Because that function is not even add it
to the queue yet, we're still counting
down the 5 s. Then it gets added to the queue. And then when there is room, it gets added to the stack. And then it begins executing
the code inside it. So here's the code inside it. And now it's got to grab greet, name and punk, but this function is already
removed from the stack. So what happens? Well, this is where
closure comes in because the JavaScript
engine knows that this function still
has a reference to these variables which are
part of its lexical scope. Lexical where it is written. And this is the scope here. So it still has access to that. These are retained in memory. Even though this function has finished executing and is
removed from the stack, these variables are not cleaned up their attained in memory. So this function then
is able to access them because they were a part
of its lexical scope. Javascript engine knows enough to keep them around to
be able to use them. So that is closure. Closure is created around those variables so that this function later on
can still access them. A very powerful feature
if you think about it, we can have something
execute and finish and still have
access to the variables. Very powerful. Okay, So
I want to save this. Then I'm going to
reduce this a bit. Let's go ahead and
open up the console. There's my initial return. I don't want to put
a name in there. Why did I not put
a name on a call that okay, Steve, like that. Alright, now we'll save it. The function is gone. It's counting down, counting
down, counting down. 5 s is up. We get good morning, Steve, as well as access to all of those variables
because of closure. So as we stay or as I stated, the function is removed
from the stack. But despite that, the variables
are still retained in memory because the engine or something else could
be referencing them. So it could be
variables that could be a function that this
function calls. Those are all retained
in memory so that their access as long as it's
part of the lexical scope, then it'll have access to them and they will not be cleaned up by the
JavaScript engine. Alright, let's do
another example. I'm gonna go to the
HTML file here, and I'm going to
add two buttons. And I want the first button
to have a button ID of one. So I'm using the
shortcut to do that. M, It is a plug-in for
Visual Studio Code. When I press tab, it creates the button for me
with the correct button ID. And I'm going to
name the button. Click Me like this. Okay, now we're gonna
put another button here. And I want this one
to also have an ID, but this one will be BTM to do, Click Me too, like that. So those are the two buttons
that we've added. Save that. Let's see if those
are showing up. Yes, they're right here. And then we get that message,
that code is still working. So if we come over here, I'm going to comment
that out for just a minute while
we do something else. So what I wanna do is create
an initialize function. This is a function
we're going to run when this page loads and it's going
to initialize some things, mainly the event listeners. So I'm going to call it a niche. She lies. And then I'm gonna put
some variables here. Maybe you can get
an idea of what I'm doing here with Closure. I'm going to set
up two variables. And both of these variables
are still going to be accessible even after this initialize function
is completely done. So the initialize function
is going to run first. It's going to set up the event listeners that
I'm doing right now. Let's see. Btn, one is one of those
that I want to do. Add event listener. And we're going to use the
click event is going to set those up and then
it's gonna be finished. But even with it being finished, we're going to still
have access to those variables and we'll see
how we can deal with that. So one of the things
we're gonna do is C and T. We're just
going to increment that first variable there and then
log to the console C and T. That's what we'll do in
this first one like that. And let me go ahead and semicolon there, and
semicolon there. And I'm just going to copy this one and basically do a similar type of thing
for the next one down here. But this time we're
going to do bt and two, and this time we're going
to increment the count, but we're gonna do with
the increment amount. So we'll do a plus equal
increments like that. And then we'll log the
count to the console again. Alright, we've got that setup. Now, when the page loads, I'm going to call initialize. So that's going to run and it's going to be
removed from the stack. However, these variables will be retained in memory
because they're referenced by these
functions here, these anonymous functions that are part of the event listener. So who knows how long it will go after this function
has completed, before these buttons
or even clicked. It really doesn't matter
how long it could be years. As long as that
page stays active, it will retain these in memory and it will have access to them. Alright, so let's save that. And now let's obviously that initialized function has
already been completed. Let's go ahead and do Click Me and we get
logged to the console. Let's click this one over here. Is it going to remember this number that was
incremented here? It does. It adds two more to it. And I click this when
it adds one to it. So two different functions, but they're addressing
the same lexical scope. So they're addressing
the same variable. And because of closure, those variables are retained. They are accessed by
both those functions. You can get an idea. Now, the power that closure
can provide in JavaScript, it is really an important
feature of JavaScript. We've provided the
first examples of closure using setTimeout and
also using addEventListener. Well, what I wanna do next in the next topic is
we're going to use a higher order function to show the application
of closure as well. So let's move on
to the next topic.
8. Using Closure with Returned Functions: When we talked about
higher-order functions, one thing that made a
function higher-order is if it returned to function. Combining that
feature with closure, we have a pretty
powerful construct. Because suddenly we can return a function from a function. And that returned function
will have access to the scope of the original function,
any variable setup. And he functions declared. We'll have access
to all of those. And one of the benefits of that is we did not have to put any of those variables are functions on the global scope in order
to make them accessible. In a sense, they are private. They can only be accessed
by things in its scope. And the return function
can continue to act on them and use them. Let's look at an example. Alright, now notice the number of things we have declared here. We have a variable, we have three functions, and then we have this
function which is created by composing the three
functions previous to it. So we have quite a bit
that's declared here and is on the global space. While using this idea that
we just talked about, Let's put it all inside
a function and then have it return a function
that will do this. Same thing. Alright? So let's just call this, let's call it Get function
for simplicity sake. And I'm gonna take
this and cut that out. And then let's go ahead
and indent all of this. Down here. Add the closing curly brace. So there's our function. We've got that setup, but now we need to
return a function. So we can do that by simply replacing this
part here with return. And it's going to return
this function here. Now to assign that to
multiply by five and so on. We can declare this variable. And we can set it equal to this function we've
just created Get function. So that when this
function completes, the get function completes, it's going to return a function
and that's going to be placed and multiply
by five and display. Alright, now this function here, even though this function above it is completely finished, it's removed from the stack. It's going to have access
to this and this and this and the num
one that variables can have access to all of that that's gonna
be available to it. And then if we change
the signature of this. So if we're just
passing in one number, let's say and two. And then down here, we use num one from this
declared previously. Now this is always going to multiply by five
and something else, whatever is passed in. So that will make it a
multiplied by five and display, which is going to
be returned here. Now we're only passing
in one number like this. Now let's go ahead
and save this. And we'll take a look at it. Open up the console here. And we should have access to multiply it by five and Display. And let's pass in six. And that gives us back 30 formats that puts the
punctuation after anyway, it does all those
other things that were a part of that function. This function here, the
get function, function, so it has access
to all of those. Now something else
we could do to even make this better is we could use num one up here. We can get rid of
the declaration here and just have
it as a parameter. Now, when we create the multiply it by five
and display function, we pass in five. But we can also
create multiplied by, let's do ten and display. Suddenly this is a
lot more flexible. We just pass in ten there. So now we have two functions that have been
created from this. And each one of
these have access to everything that's a part of the lexical scope of this
function that's returned. So becomes, becomes
very powerful that way. So let's just check those out. Let's do our multiply by five. Let's do seven this time. So that's still working for us. And now we also have
a multiply by ten. Let's do seven on
this one as well. So we've got two functions now that have access to
everything that's inside of this. The scope of the get
function function, even though that function
is no longer running. The JavaScript engine
is smart enough to know that there could be something that's
still references the so it creates
closure over that. Those are maintained in memory. And because of closure, we're able to access them. Now, let me show you
something else we can do just as we're dealing with higher-order
functions here, enclosure. Let me go ahead and
go to the console. I'm going to call get function. And I'm going to pass
in 20 this time. Now what does that
going to return? Well, it's going to return a
function as we can see here. Now, since that is
returning a function, I could do something like this. Since the function
is being returned, I could immediately invoke it. The next set of
parentheses will invoke the function that's
being returned. And I'll pass in five, and so that should equal 100. Now we've got a function. If we just use gap function this way we've got a
function where we can multiply any two numbers
and display them. Now what I'm trying
to show you here is just the flexibility because of the higher-order function, because of the closure
that has been created. And that's why I said it's a, it's a powerful construct
in JavaScript and one we need to be familiar with and we need
to be able to use. Alright, let's move
on to the next topic.
9. Important Features of Closures: Now, I know I've been
harping on this a lot, but closures are important. I want to use this topic to
point out two features of closures that make
them important. Now these aren't the only
features of closures. But two that I want to
make sure you understand. The first feature is that
closures can help us efficiently use memory
or CPU intensive tasks. Now let me give an
example of that. So here's our code that
we were using before. And let's say that as
a part of this code, we have a process that retrieves data from a database or from an API on some site. And what we get back from that
as we get this huge array. Now I'm going to
represent this huge array just with a small array. But think of it as a huge rate. This is the data that
comes back from the site API using some sort of
asynchronous command. We'll get into
asynchronous stuff later. But we have to deal
with it asynchronously because it takes a long
time for it to come back. But when it finally
does come back, we get this array of numbers. Alright? And then we are
changing this to an index. And basically what
we're doing is we're grabbing from the huge array the number that we're
going to choose. Okay? Now, let me emphasize again
that in retrieving this data, it takes awhile for
it to go out to the database or to the site
and get it and bring it back. So we have to deal with
it asynchronously. Now think about if each time we wanted to multiply
numbers together, we had to do this
intensive task. We had to go out
and get that data. Each time we did that, it would take the seconds
or whatever it is, even if it's a minor
number of seconds, even milliseconds, those can add up each time we go
out and do that. So it can be intensive. Well, if our function, function goes out
and gets it once, and then we have it
stored in this variable. And then through closure, we're able to continue to
access it using the Multiply by five Display and then
multiply by ten display so that each time we want
to multiply by five, we don't have to go
out and get this data. Each time we call this function. It's just referencing what we already have stored in memory. It's already done the
process to get it. Alright, so that's how it
can help us efficiently used CPU intensive or time-intensive or memory intensive tasks. By using Closure, we can make that continually
available for us. Alright, now, the
second feature, feature I want to talk about,
we call encapsulation. Now. In order to understand what
an encapsulation as let me just expand on this idea. We've got where we
have this huge array. Let's say that
this is something, this array is something that
we don't want to be changed. Willy nilly, in any
part of the program. There's only one place we
want to be able to change it, and no place else in the program should that
be allowed to happen? Well, we can set up a
function, something like this, where we pass in a
new number and then that new number is added to the array and that's the
only way it can be updated. Okay? So we just do a push
here with new num. So we don't want people
to be able to access is array and be able to
add numbers to it. In fact, perhaps, every time somebody
adds a number to it, we want to check it somehow to make sure it meets
some criteria. So we can have an
if statement here. If num is greater than 100, Maybe that's all we're accepting
or something like that. Then we'll go ahead
and push it on. So we control the
adding of new numbers to that array using
this function. So then the only way people can manipulate the array
is with this function. They have to go through this. Now, right now
we're returning to functions which obviously
is not allowed. A way we can do that if
we have two functions, we want to return from
something like this, is we can return an object. So if we just change
this function too, Update array like that. And we change this one to
create function like that. We could then return an object. And we'd have update array and create fun. They would both be a
part of that object. So that when we
call this function, the return is an object. So get function. What we get back is an object. And then we can use that object. We can do OBJ to
update array to call this function or OBJ dot create fund to
call this function. So anyway, that's how we would do that instead of
doing two return functions. But the point I want
to get at is now we've created a function that this is the only way we can
change this array. So we've enclosed this
array inside a function. We've encapsulated it. So this is encapsulation, it protects it only way, one way to change it and we
can check as that is changed. And really these other functions are encapsulated as well. They're not available
outside of this function. The only way we use
them is with this here. This has access to them, but nothing else
has access to them. So these are encapsulated. The assay, the idea
of encapsulation. Both of these features are important features when
it comes to closure. Alright, let's move
on to the next topic.
10. Exercise Start: Closure 1: Alright, it's time for
a closer exercise. Now I'm going to
present the problem to you in this first video, and then in the next topic
we'll go through the solution. Now, this particular problem is something that you
can see on the internet. It's a problem is many times presented to illustrate closure. Maybe a part of JavaScript
interview as well. So it's very practical
in the sense that it's the kind of problem
that people present to see if you do
understand closure. So let's take a look
at what that is. Alright, so I have an array
here and rate of learners, and they're just names, first names in this array. Learners total of five.
That's all there is. Then we have a for-loop and we are looping
through that array. We've declared the variable. We go through the loop while it's less than the
length of that array. And then we incremented here. And then inside of that
loop we have a set timeout. And this is the function
that gets placed on the queue once the
time has expired. So setTimeout is handled by
the browser, the web API. And when that 2 s expires, then this function
here is placed on the queue and the event loop, as soon as it has space for it, it adds it to the stack and
that function is executed. Okay, so we know
that whole process. Now let's just go ahead and see what the results are from this. We're looking at this. What is it going to
display console log. So if I open up
the console here, basically I get five
undefined statements. That's all I get on the log. So when it is logging
to the console, it can't find anything
in the array, and it just prints
out undefined. So this has two parts to it. This exercise has two parts. First, I want you to
think about and be able to explain why there
are five undefined, Why does that happen? And explain it in terms of things we've learned
about scope. The second part is
to then use closure to solve this problem so
that that doesn't happen. So that we actually get
logged to the console, the names that are
here in the array. So two parts to that exercise. Now, I will say right now, there is a simple way
to solve this problem, but I want you to use
closure to solve it. We'll talk about the simple way at the end of the solution, because I think
it's important to understand that as well. Both closure and both
this other concept are both important
to understand. So take some time. When you're ready, move the next topic and we'll
go through this solution.
11. Exercise End: Closure 1: How did you do on that one? I hope you are able
to solve that. Let's first talk about why we're getting
the five undefined. Let's do that first. So notice everything here is not created
inside a function, so it's going to be
on the global scope. So that's on the global scope. This var declaration, the eye, that's on the global scope. Alright, so that gets
placed on the global scope. Then we set off our
first setTimeout. That's handled by the browser.
Two-second start counting. The for loop keeps going. And so basically it does five of these five setTime out really quick after another
and they're all set for 2 s. Alright? Now, by the time we
get to that last one, the last iteration of this
for loop i is incremented. And so I at that
time becomes five. And I is on the global scope. So once this 2 s is
done for the first one, that function is
placed on the queue. It gets picked up
by the event loop and placed in the stack. It invokes. This line here is executed. Learners five is undefined. We have 012345 is undefined. That's why we're
getting the undefined. So what we wanna do
is we want to set up closure so that we close over a variable that
can then be used here. And it won't be using
the global variable I, which gets changed each time we iterate through the for-loop. Alright? And by setting up a function, we define a new scope. And so the closure
is handled for that scope and the variable
that we use within that. So let's go ahead and look
at how we might do that. There's a couple of
ways to do this. But the first one, I'm just going to
create a function here. And I'm going to do a
function declaration this time just to keep it shorter. I'm going to call
it show learner. And then let's just go
ahead and cut this. And we'll paste this
inside of that function. So because we've set
up a new function, we've defined a new scope. We can now place a
variable inside that. So let learner equal and I'm just gonna
set it to learners. And then the index I. So we're going to assign one of the names to
this learner variable. And that is exactly what
we're going to display here. And so because of closure, when this function fires, it will have access
to this variable. And each time this
function invokes, it will create a
brand new variable for the new scope
that's created. And so down here, I would need to
put show learner. So it's invoked each time
through this for loop. Now, when we get into immediately invoked
function expressions, there's a simpler
way to do this, which we'll look
at at that time. But for right now, I'm just
invoking the function here. It calls this, sets up a variable inside of
that function scope. This function because it
references that variable. And because of closure, that variable will be retained in memory so that it
has access to it. And that should solve
the problem for us. So if I say that after 2 s, we get all the names displaying. Alright, so that's one approach. I'm going to copy this.
So I have a version of each of these in the
code that you can look at. I'll just comment
out that one there. So another approach
would have been set a variable idx maybe for index and just
simply set that to I. Okay, so this variable is
now part of this scope. So that's gonna accomplish
the same thing. The only difference
is down here. Instead of i, we use idx to reference the
position in the array. And that will work
just as well for us. If I save that, we jump out here after 2 s, we can see the names displaying. Alright, now I mentioned there's a simple solution
to this as well. So let me show you what
that simple solution is. Let me copy this. So these first two solutions, Using closer, let me just
make a comment there. Using closure. Comment that out. So we're not dealing
with that anymore. The second one is simply
using the property of LET. Now, if you remember one
of the differences we talked about with let and
const as opposed to var, is that Latin cons
have block scope. What is blocked scope mean? In the case of this for-loop? I'm going to remove
this really quick and let me get rid of that. We're just going to put it
back to the way it was. And so I want to use I
here to reference those. Now, back to the
idea of block scope. What is walk scope mean? Well, the scope is right here. And so because
it's block scoped, if we change this to
lat instead of var, it's already scoped
inside of this. And this function will still have reference
to it through closure. So the variable I will
be maintained in memory. And each time through the loop, basically it's declaring
a new variable i. Because of the block scoping
that we get with let. Alright, and so each of those functions will have
a reference to that I. And that will solve
the problem for us. Okay? So this solves the problem using a feature of let that we
sometimes forget about. We forget that the block scoping can do this type
of thing for us. But let me just show you,
I'm going to save that. Jump out again after 2 s. Same results, same results. Now I think I mentioned when
I was talking about that this solution doesn't
really use close. Well, it does use closure. We're still closing
over a variable. Now, function styles
reference to it. But the reason this
works and var doesn't is because lat has this
block scope here. Var does not have block scope, and so it was scoped
to the global context. So that's another solution. Now, if you weren't able
to get to that solution, I hope at least
you understand it. I hope you see how these use closure to
solve the problem for us. And I'd like you to
do one more exercise, so we're gonna do one more next. Let's move on.
12. Exercise Start: Closure 2: I'm gonna have you do a
second exercise on closures. As you can see, I've added three buttons
to this HTML page. And this exercise involves
those three buttons. Let me go ahead and
jump to the code file. I have a description of what
I'd like you to do there. And these are the same code files you will use
for the exercise. First off, up here at the top, I've gone ahead and created
three constants that have the buttons that I've
created on an HTML page. These three buttons here, your references,
those three buttons, I've gone ahead
and created those. You can use those or you can
create your own whatever. I just added that in
case some were unsure how to select those
buttons from the DOM. Now here's what I'd
like you to do. Each time one of those
buttons is clicked, it should display two numbers. The first number it
should display is the amount of times that
button has been clicked. And then a second number is the cumulative value
of all three buttons. So it should say
something like this. I've been clicked three times. All three buttons have been clicked ten times,
something like that. And it's important that you use closure to make this happen. Now, be aware. There are hundreds of ways
to solve this problem. There are hundreds of ways outside of closure to solve it, but there's hundreds ways
using Closure to solve it. So your solution is probably going to look a bit
different than my solution. The point is, I want
you to use closure. I want you to get practice
doing that and thinking about your code with closure as a
tool to solve these problems. So that's how I'd like
you to address this. Alright, go ahead and
give that some time. Once you're ready to move
on and see the solution, go to the next topic.
13. Exercise End: Closure 2: Alright, let's go through this. Now I'm pretty certain that my solution is going to be
a bit different than yours. I suspect that what a lot of you did is you created
an outer function. You declare three
variables, four variables, actually one for the
total account and then perhaps a variable for
each button count. Then you would
increment those at the appropriate times and display the appropriate message. I'm going to take a little
bit different approach in solving this solution. I wanted to make sure I
use the DRY principle. I didn't want to repeat things that I didn't need to repeat. I'm going to have
a single function that's going to display. I'm going to have a
single construct. It's going to add an event
listener to each of these. And basically I've
eliminated the use of any IF statements at all as able to do what I
did because of closure. As I'm sure your solution
use closure as well. So let's go ahead and
get started so I can show you my solution. We can learn from it together. So I'm going to first set up an initialize function
that's going to be the outer function that's
going to establish all this. And then I'll want to invoke
that to get things started. So I'll put that down here. Double prints to indicate that we're invoking
that function. Now what I'm going to do with these declarations here is
I'm going to set up an array, just going to call up buttons. And this array is going to contain each one of
these declarations. Now the reason I'm doing
this is I'm going to declare the advanced
listeners with a loop. And so I want to put these in an array just to make
that simpler for me. Because then I can just
loop through that array, grab each item, each element, add the event listener,
then I'm good to go. So there's my array. Now I need to set up
another variable. This is going to be
the total count. This needs to be a part of this over all the scope of
this overall function. Because it's going to need to be incremented by
all three buttons. So I'll initially
set that to zero. Alright, Now, as I was
thinking about this, I figured, well each of
these buttons are going to display the same message. And so I really should have
one function that can display that message in each
of these buttons is going to increment the
total count variable. And so I should have one
function that does that as well. And so I thought, well
I can put those things in a single function. So I'm going to set that up now. Increment and display. If I can type counters, that's what I'm
going to call it. Right inside there,
I can immediately increments the total
count variable. And then I can log to
the console the message. And I'm going to use a template string just to make
this a little bit easier. And I'm going to copy, I'm just going to copy the exact same phrase right down here. That's what I wanted
to display anyway, so I'll just copy that. Now in the place of the
total count, this one here. I need to put the
variable total count. And what am I going to put here? Well, I think what I'm gonna
do is I'm going to pass in the count from each button. And so then I can replace this
with that past invariable. Since that's a parameter. The scope of that
variable is here, whereas the scope of total
count is all of that. So when I create the event
listeners down here, it'll be able to
incremental account. And this function
here will also have access to total count
through closure. So it's going to be available. Alright, so now
let's go ahead and increment the event listeners. And like I said, I set up an array so I can
do that in a loop. So cycle through this. And this allows me to do
the same code only once. Because setting up
those event listeners would be the same code. Now, here's what I want to
do inside of this for loop. I'm going to declare a variable
and I'm going to use lat. So the scope of that
will be that block. And I'm going to set it to zero. So this is a different variable than this because they
have a different scope. Alright? They're not
conflicting with each other even though they
have the same name. And I'm setting that up because in the EventListener I'm
going to set up a function. That will then have access
to this variable and we'll increment that variable and
then pass it into here. Alright. So each time this is called, it's going to have a
different variable or possibly a different
variable passed in. And because of closure, I'll be able to keep
track of the total count. I'll be able to keep track
of the individual count. So now let's go ahead and
set up those event listener. So BTN, using the for loop, btn now contains each of these DOM elements as it
iterates through that array. So BTN, add event listener. Then we want to use
the click events, and here's my
anonymous function. Now what are we going to do inside this anonymous function? Well, first we're going to
increment this variable here. This function will
have access to that variable through closure. So to keep track
of the accounts. Once we've incremented,
then we'll go ahead and call increment display counters. And we're going to
pass in that variable. This variable here that's been incremented will get
passed into here, and then it will
get displayed here. And this variable
that is a part of that scope will simply be incremented each time
the function is called. And because I've looped through all the elements in the array, all of these buttons will have
this same event listener. So we're all going to
call that same function. Because this is a loop, this will be a different variable each time
through that loop. And then the functions
for each event listener. Well, I've access to
it because of closure. Alright, let's go ahead and
see how that works for us. I'm going gonna go
ahead and save that. And we'll jump back out here. And let's say I want to display the console so we can see
the counts we're getting. So let me scroll down
to the buttons show up. And if we click button
one, what do we get? One time all three buttons
have been clicked one time. Let me click it
again. Two times. All three buttons I'm
going to click two times. Now scored a button to
onetime, three times. Let's go to Button three. Onetime, four times
button to again, two times, five times. It looks like it's working
two times, six times. Alright, so a fun little
exercise using closure. So I hope this exercise
was WE educational. Not only did you
get a chance to try to figure it out on your own. But also perhaps you can learn something from the
approach I took as well. Because like I said,
there's probably 100 different ways to
solve this problem. Alright, let's move
on to the next topic.
14. Immediately Invoked Function Expressions: Immediately invoked
function expressions are an important
pattern in JavaScript. I've mentioned it
briefly during a few of the past topics. Well, now we're going to
look at it in more detail. Immediately. Invoke
function expressions are called IFIS in the
JavaScript world. That is the way you
pronounce that IIFE that you see at the end there
on that title line. Iffy. And if he is simply defining a function and then
invoking it immediately, we don't wait to call later. It's defined and in
bulk at the same time. Let's look at a simple
example and then I will talk about some
of the reasons we use. If he's alright, I'm going to create a very simple
function here. Basically going to add two numbers and
return them as well. So we'll return, Let's
just do five plus five. Now, if we save this, and I'm going to jump out here and take a look
at the console. If we look at the sum variable, what it contains, we see that
it contains the function. Now, if we want to invoke that, then we have to add the purines. Now, what if we
could define this? And then just put the
double parentheses at the end of it here so that we're defining the function and then we're invoking
it at the same time. That would mean it's
immediately invoked. And this is a
function expression. So an immediately invoked
function expression. So let's try that. I'll go ahead and put the two
quotes after that. Now what is going to be
in the sum variable? Is it going to be the function? Know, it's going to
be the value that's returned if this
immediately invoked. So we'll save that. And then let's take
a look at some. Now, it contains the response or the return value from that function because it
was immediately invoked. So this here is an immediately invoked
function expression. It does not work for a
function declaration. We can't do this type of thing. Let's see return. Let's do something like that. I want you to show you what happens if
we set up a declaration. So if I save that
uncaught syntax error, unexpected token on line nine. So why nine doesn't like this? It doesn't know what
we're doing here. So it can't be done with
a function declaration, has to be a function expression. So anytime we're immediately
invoking something is a function expression. Now, let me show you type of thing that can
be done with this. I'm going to do a sum ten, and I'll set that
equal to a function. And we're going to have a parameter there for a
number that's passed in. And then inside of
here we're going to declare a variable and we'll set that equal to
ten, just like that. And then we'll
return num plus one. So that's why we're
calling it some ten. Now what happens if
we immediately invoke this footprints around that? Save it. Let's take a look at some ten. Nan is telling us
it's not a number. What is it telling us
that for a while we didn't pass a value in for this. And so it's trying to add
undefined to ten, says NaN. So let's pass a value
and we'll do five. Save that. Now we get 15 with some time. Now, I want to make you aware of something with this variable
that I just put in here. There is nothing that can change this variable
once it's set. It is ten. And it's not just because
I used a constant defined, obviously a constable
prevent that from being reassigned will
get a syntax error. But it's also because it's
contained in this function. The fact that is defined in this function means we
don't have access to it, no other code or
could even dress that variable because
it's inside the function. Alright? So the reason I show
this is this helps illustrate the use cases for immediately invoked
function expression is there actually is two of those. I'm just going to
enter them here. Use cases to that I
think are important. One is private data. Okay? This is private data. This can't be changed. It's inside the function, can't be messed
with, it's private. Another use case is to avoid global variables and
variable collision. So we are able to run code without declaring
global variables when we use an immediately
invoked function expression. Now let me illustrate
that use case. So I'm going to copy
in some code here. I'll just paste it
below these use cases. There we go. Title too. I'm query selector title too. I'm grabbing, we
look at HTML file. I'm grabbing this div
right here that has the immediately invoked
function expression tidal line. Alright, we're grabbing that. Then we're adding
event listeners to it. One is for mouseover,
ones for mouse out. In both cases, all
it does is change the cursor and change it back. And then we have a click event that simply logs to the console the
inner text of this. Alright? So if we save that,
we come out here. Notice my cursor changes. As I go over that. When I click it puts
the information, the innerHTML from that DOM
element on the console. Now we've declared a
variable here to do that, to grab this div and
to be able to use it. But let's put a
function around this. Let's start by
declaring a variable. I'm going to change
this in a moment, but we're going to
start this way. Let's say a knit, it's an initialized function. And let me just put all of this. I'm going to indent it. So that can be inside
these curly braces. Format a little bit for us. And then here's
the closing curly brace for that function. Now we have an init function. Now, obviously if we save this, we no longer have the
functionality here because it hasn't been invoked. We did not call that function. Well, we know that
we can immediately invoke that by doing
this kind of thing. So I add the prince
at the end there. Now let's see if we've
got that functionality. I come up, the cursor
changes, I click on it. Yes, we've got it. So we were able to
immediately invoke that, but we still have
a variable here. Well, we're not capturing
anything that's variable. There's nothing that
we're returning from this function that we need
to have the variable for it. Let's just remove that variable. And let's see if that works. We save it. What do we get? A syntax error
function statement returns a requires
a function name. So what is telling us, what that syntax
error is telling us is that this is a
function statement. It's expecting a function
name right after. It's expecting a
function declaration because it sees the
function keyword is first. Well, let's turn this
into an expression. And why we can do that is simply put parentheses around it. Now I usually like to put my parentheses
around the function and then have the brands to
invoke it right after that. But there are many people
that prefer to do it. This way. They both work. It doesn't matter which
way you choose to do it. They both work. So now let's save this. We no longer get
the syntax there. I come up, I get the
cursor changing. I click on it, I see it
down in the console. So now we have code that's
executing inside a function. And we didn't have to declare variable to have that happen. This variable is now
inside the function, doesn't pollute
the global space. So we avoid variable collisions, meaning that someone else working on a project
or some cold we brought in had was using the same variable name
and those two variables, Clyde, the last one
to be declared or last one to receive a value is the one
that takes precedence. So we avoid those collisions and we avoid global variables. Now we can also
have private data. Obviously no one can
access this variable, but this DOM elements available
outside of this function, they would just
need to select it. But I can declare
a variable here, set it equal to something. Just punctuation or some sort. Now this cannot be
accessed from here on out. The punctuation is going to
be an exclamation point. Well, we could also set
up a function inside of this function and return
it outside the function. That would allow
us to change this. And then we govern how that
private data is changed, which is a very common pattern. In fact, this is a pattern that's used in the
traditional module pattern, which we'll talk about when we deal with
modules in this course. As I mentioned, with closures is going to be looking at
that and you're going to be looking at immediately
invoked function expression when we deal with the
traditional module patterns. So it's a great pattern to
learn to apply these concepts. But this punctuation
mark is private. If I save this, come out to click on it. Now we're seeing the
punctuation mark there. So that is immediately
invoked function expressions. Now what I'd like to
do in the next topics, we're going to look at a few of the pieces of code we
used in past topics where I may have mentioned that this could be enhanced with immediately invoked
function expression. We'll look at how we
can enhance those. We'll look at the changes we
need to make to use an iffy. Alright, so let's move
on to the next topic.
15. Applying IIFEs: Now that I've introduced IFIS, let's apply them to a few of the code examples we've
been using in this section. These are examples of closure
and now we're going to add IFIS to that same code. Now, the first example
is the delayed greeting. Now, this is a simple example. If you remember, we
have a function. We call delayed greeting
pass in a name using setTimeout that greeting
is delayed by 5 s. Now, if this were a functional
wanted to call from somewhere, then we wouldn't use
an empty for that. But I want to use NFV. Let's say I wanted this to
display when the file loads. And so I want to use NFV for this example because it has
this pass in a variable. So I want to do an
example of that. Let's go ahead and look
at how we would do that. Very simple. We just need to remove this. We don't need that anymore. And we can remove
this part as well. Now, we want to turn this into an expression so it's valid and so I put parentheses
around that like that. And then to invoke it, we put parentheses again. Now as you know, there are
different formats for this, this last Perrin could
go out here as well. I just prefer this
particular structure. Now what we need to do
is pass in the variable, and so I just put that
inside of the parentheses. That's all we need to do that. And there we have our
delayed greeting. So let me go back here and
let's open up the console. Here's our greeting from when
we first loaded the page. Now, let's go ahead and save
this and it will reload. And then after 5 s, we should get the
same greeting again. Basically we're just
removing the line that invokes this function and
we're handling it here. That's really what
we're doing with an immediately invoked
function expression. Alright, now I'm going
to comment this out. And I'm going to copy in another piece of code that
we used as an example. And this was an
initialized function. Go ahead and paste that in.
And if you're a member, it's initializing two buttons. And when they are
clicked, increment the count variable and
then log to the console. Now, in order to use this, I need to come here and uncomment those
buttons so they will show up on the HTML page. So go ahead and refresh that. And let's say this one. Let's just see if
those are showing up. We have them right here. Okay. Just make sure that code's
working before we move on. Yep. Alright. So we are good. Now when we have
some things to be initialized and we haven't initialized function like this. That's usually a good
application for an iffy. Since this function is going, only going to be run once and
it's when the page loads. Why store it in a variable? So we can call it later. Or why declare the function
so we can call it later. Let's just invoke the code, run the code, and
be done with it. So let's go ahead and remove
that declaration there, and we'll remove this down here. Once again, all we need to do is surround this with Krenz. That makes it valid. And then we put the plans
after to invoke it. Now this is really
going to accomplish same, same thing for us. So we'll save this,
the page reloads. And let's go ahead and
try these buttons. And they are still working. So two quick examples where
we took something that we did with closures and we added an immediately invoked
function expression. And especially the second
example is ideal for IFIS. Alright, let's move on
and let me give you a chance to try an
exercise on these.
16. Exercise Start: IIFEs: Once you understand
the structure of an immediately invoked
function expression, they're not that
difficult to create. Usually you're converting
something that's already there into one and so that
makes it even easier. But I want you to
do an exercise. This is an important
concept and I think it's important to do an
exercise on this concept. So let's take a look at what
I'd like to have you do. Alright, here's some initial
code and basically all it's doing is it's creating a message inside of
this message variable, saying something like
today is whatever the date is and then
the day of the month. That's all it's doing. This
is something that might display on initial webpage
or something like that. So what I'd like you to do
is to turn this into an iffy and to see whether
it's working correctly, just log the results
to the console. So we'll send it to the console. It should produce as soon as the page loads and
logged out to the console. Normally you may want to display this message inside of some
div or something like that. We'll do the console and
that will be good enough. Alright, go ahead
and give this a try. And when you're ready to review, move to the next topic.
17. Exercise End: IIFEs: Okay. Hopefully that wasn't too hard. I didn't intend that one
to be too difficult. Now, just to mention one of the advantages of
turning this into an FE is there suddenly three variables that are
currently on the global space, that won't be on
the goal of space. So big advantage, they're
making this an iffy. So let's go ahead and do that. I'm going to enter
function first. And then my curly braces, I'm going to go ahead
and take the code now and put it inside
of that function. Notice I did not give
the function a name, which usually means I'm in the process of
creating an iffy. But I do need to surround
this in parentheses, turn it into expressions
so we don't get a syntax error and then
parentheses to invoke it. Now the one thing I did
mention that we want to do is we just want to display
this to the console. So let me go ahead and do that. Console dot log message just to make sure it's
working correctly. And we'll save that. Jump out here and take
a look at the console, see if we got a message. Today is Monday 19. And that is indeed what the day of the week is and
the date of the month. And that is working for us. So pretty simple. But a very important
pattern and JavaScript immediately invoked function
expressions or if he's, alright, let's move on.