Instructor: We have learned a lot
of theory up until this point, but now,
you are ready to understand one
of the most crucial and advanced things
about JavaScript: closures,
and this is probably one
of the most difficult-to-understand topics for beginners,
but you already know everything that you need
in order to understand and use closures.
So let's dive right into this lecture.
So as our example for this lecture,
we want to write a small function
that returns a function
which calculates how many years we have until retirement.
So let's quickly do that.
So function, and let's simply call it retirement,
and we pass into it the retirementAge,
so the age at which someone can officially retire.
So for example, here in Europe,
it's mainly 65 years, usually.
Okay, and this function will then return another function
which will actually calculate the years
that someone has left.
So we already did this in the last lectures,
so let's not do it again.
So we simply return an anonymous function here.
So we don't have a name, all we have is a parameter,
and this is the yearOfBirth again.
So we start by calculating the age in here,
so 2016 minus the yearOfBirth,
and then we log to the console,
the retirementAge
that we passed into the first function, right?
Minus the age that we just created,
and then let's add something else,
like a string to make a sentence out of this,
and I'm calling this one, a,
which I didn't declare yet,
so I'm going to declare it here.
So var a,
years left until retirement.
So I will explain you in a second
why we actually wrote this function like this.
It's because we want to use closures here,
so I will explain you in a second
what closures are and how they work in here,
but for now, let's just write this function,
so, as it is.
And now, let's try to use this function,
and, as you know, this returns a function,
so we can store the result
of calling this function in a variable,
and then this variable will be a function as well.
So as you noticed, we passed the age
that someone has to have in order to be able to retire.
So this is an age that changes from country to country,
and so we can basically create one function
for each country.
So this is similar to creating the interview questions
for different jobs, like we did before, right?
So let's create a function here for the US,
and I know that in the US,
the retirement age is actually 66,
so we call our retirement function
and then we pass 66 into it,
and this will return a function
where the retirement age, so this year, is 66.
So if we now call our newly created function,
which is this one here, right?
So retirementUS,
and, of course, we need
to pass the year of birth, right?
So let's use our well-known 1990, okay?
And then, let's check it out.
Alright, so 40 years left until retirement,
or we could also write it like this,
like we did before,
so, for example, retirement,
then pass an age like 66 again,
so this will return a function,
and then we can simply call this new function
with the yearOfBirth again.
So this should give us the same result,
okay, so 40 years again.
So this works,
and let's take a look at what just happened here.
So let's examine this together.
So we started by calling the retirement function
and passed the value of 66 here, right?
The function then declares this a variable here
and returns this function.
Then the function finishes,
and its execution context gets popped off the stack,
and you remember that part, right?
Okay, so we stored the returned function here
in the retirementUS variable, right?
So here we call it.
And now comes the cool part.
So in here, in this function,
we use the retirementAge parameter
of this outer function here,
and also the a variable that is also declared
outside of this anonymous function, and still,
when we run this, this works, so somehow,
we are able to still use these variables even
after the retirement function,
which declares these variables,
already stopped its execution.
So think about that again.
Our inner function here is able
to use the retirement variable and a variable
of this function here that is already gone.
It has already returned.
But somehow the variables are still there,
and this is the closure.
This is really fascinating, right?
This really blows my mind each time that I use it, really.
So now that we know what a closure is,
let's see how and why this actually works
behind the scenes.
So again, we can summarize how a closure works like this:
An inner function has always access
to the variables and parameters of its outer function,
even after the outer function has returned.
So let's see what happens
when we call our retirement function.
As we already know,
the new function gets a new execution context
that is put on top of the execution stack.
That execution context has an object,
which stores the variables.
The scope chain ended this variable.
So let's see the scope chain for the retirement function,
which means the variables that the function has access to.
And remember, the scope chain is like a pointer
to all the variable objects that the function has access to.
Alright, so of course, the function has access
to the retirementAge argument, set to 66,
and a variable, that holds our string.
Okay, and then the function returns.
So, after the function returns,
now the execution context
of the retirement function is effectively gone,
and with it, the variable object
and the entire scope chain should be gone, right?
Actually, no.
The secret to closures is that,
even after a function returns,
and execution context is gone,
the variable object is still there.
It's not gone.
It still sits here in memory and it can be accessed,
and that's why we still it there
in the execution stack on the left side,
and also in the scope chain on the right side,
because, and I'm sure that you remember this,
the scope chain is in fact a pointer to variable objects,
and in this case, the variable object
that we have here on the stack.
So let's see this in action.
Let's call the inner function,
that we effectively called retirementUS,
with the argument of 1990,
which puts, of course, a new execution context on the stack.
Let's now look at the scope chain.
So since this inner function is written lexically
in the retirement function, it has access to its scope,
and you already know and use that.
And now here comes the magic.
Since the variable object
of the retirement function is still there,
the scope chain stays intact.
It keeps working.
And so, we can access the variables
that were created in the retirement function long
after the function has completed execution,
and after its execution context is, of course, gone.
The current execution context has closed in
on the outer variable object,
so that it can use it,
and that's why it's called a closure.
So the scope chain always stays intact.
This is the most important thing
that you have to understand and remember.
Okay, and just to finish this,
the function simply returns,
and the context is popped off the stack, as usual.
So now you not only know what closures are,
but you also know how and why they actually work.
And note that we don't create closures manually.
This is something that's really built into JavaScript.
We don't have to worry about anything.
We don't have to say that we want the closure.
JavaScript will always do this work for us automatically.
And now, the summary makes even more sense to you, right?
So an inner function has always access
to the variables and parameters of its outer function,
even after the outer function has returned.
So let's now see how this function
that we created can be useful for us.
So we can create three different functions
for countries with different retirement ages,
and use these functions over and over again.
So this is similar with something that we did before, right?
So we have a more generic function up here,
the retirement function,
which we can then use to create more-specific functions.
And this is only one of the many application cases
of closures, and we will see more of these later on
in the course.
So let's now create some more functions.
We just get rid of this here.
Okay, so let's create a retirement function
for Germany,
because in Germany, the retirement age is,
not 66, but 65.
Okay?
And we can also create one
for another country here in Europe,
which is Iceland, which has an age of 67.
So Iceland,
we will call the retirement function
with an argument of 67.
And now we can go ahead and use these functions
for different people in these different countries,
for example, and see how many years they have left.
So let's use these three for the same people,
imagining that they lived in Germany,
so the retirementGermany function,
and that they lived in Iceland,
so retirementIceland, and then also 1990,
and if I now run this, we have three different ages,
actually, three different years,
that the person has left until retirement.
So 39 in Germany, 40 in the US, and 41 in Iceland.
And all of this is possible thanks to the power of closures.
Okay, now, just to finish this,
I have a very small challenge for you, and this challenge is
that you should rewrite the interviewqQuestion function
that we wrote in another lecture,
but this time using the power of closures.
And the function that I'm talking about is, let's see,
yep, it's this one here.
So let me copy it,
paste it here,
okay, and I'm gonna comment it out, okay?
So again, I now want you to write this,
using the power of closures.
So please pause the video now, and do that, okay?
Okay, so I hope that you managed to do it.
So let's now see the solution.
So of course, we again write the function,
and it's again called interviewQuestion.
And we still accept the job,
but now the difference is
that we will always return the same function,
so there's only one return keyword in here, okay?
So one function, which accepts the name,
and then we do our if/else statement right in here,
and that is possible because of closures,
because we will be able to use the job argument,
this one, right?
Right here into this function,
even after the interviewQuestion function has returned.
Right?
So let's now write our if/else statement in here.
So job,
designer,
and I will then copy the code from up there,
so then else if job is teacher,
and then the else part.
Okay, so if it's a designer, it's this code.
There's of course no need to write this again.
And this is for the teacher
and this is for all the other jobs, basically.
Okay, so let's now use this function for a teacher.
So, interviewQuestion,
let's say, teacher,
and then we can call it right here.
There's no need to save it in another variable,
as I already showed you, right?
And let's now run this,
and it works.
So what subject do you teach, John?
So we see that this clearly a question
for the teacher, right?
So again, the difference between the two functions is
that now, the decision is taken right inside
of the function that we return, and that's possible
because we can use the job variable
to take this decision here, even
after the interviewQuestion function has already returned.
So when we first wrote this function,
we didn't know about closures,
so we wrote it this first original way here, right?
But now, we don't need this anymore,
because now we know about the power of closures, right?
And so we can harness that power and effectively use them,
because this is a better way of doing it.
This is cleaner code.
So we have only one function,
and then the if inside of here.
So let me explain it one last time, okay?
So this function call here will return this function here,
okay?
And then, we call this function
with the John parameter, the John argument,
and then this execution context will close in
over the variable object of the function that we had before,
that we called before.
So it will close in on the variables that we defined
in the old function, which was the job variable,
and so we can use this variable right
into this function as well, and we do that in here.
So here, in our if/else statement, we use the job variable
of the interviewQuestion function that has already returned
by the point that we use this inner function here, right?
So now, I hope that this is crystal-clear to you.
Alright, and this was closures.
And as you have seen, they allow us
to do really powerful things,
and you will see that in our project later.
So make sure that you really understand closures.
And I hope that you can see now why it was so important
to learn all the JavaScript theory that I showed you before,
because without that, you would not be able to understand
what I just showed you in this lecture,
because this was really, really advanced stuff.
So if you understood this lecture,
then nothing can stop you anymore on your path
to become a really amazing JavaScript developer.
So how cool is that, right?