- [Instructor] The third and final
building block of closures
is returning a value from a function.
And in particular,
returning a reference to an inner function.
Whatever a function does,
it mainly affects the app that it's part of
by returning a value.
Data goes in, and the data that comes out
has been transformed in some way by the function.
For instance, this function
takes in data in the form of the base and tax parameters.
It then uses those parameters in a calculation,
that calculation results in a new value stored
in the total variable.
And finally, it returns this new value
as the result of the function execution.
In our updateClicks function,
instead of simply calling report clicks
at the end of the function,
we can instead return a reference
to the reportClicks function.
And this has a few positive effects.
First off,
remember that including parentheses after a function name
always calls the function,
and that's not what we want to do here.
Instead,
we want to return just the function name as the value,
by returning this inner function, reportClicks,
it can be called at a later time
at the place in our code where it's being returned.
Now, outside of our updateClicks function,
we'll create a variable, I'll use the "const" keyword.
The variable will be called "report."
And its value will be the result of calling updateClicks.
Because updateClicks returns a function,
the "report" variable stores a reference
to that inner function.
And to make that inner function work,
we'll have to make a couple tweaks to our code.
The value of the "button" variable
will have to be determined
when the report function is called,
which corresponds to the inner reportClicks function.
We have to move the code that sets the value of "button"
within the inner function.
It's best practice to instantiate the variable just once,
so we'll change the "let button" statement
in the updateClicks function to just declare the variable,
but not set the value.
Then, in the reportClicks function,
we'll set the value of "button" to menu.id,
which will still correspond
to the ID of the button that was clicked.
And we can simplify our code even further
by consolidating these final two statements.
Instead of creating a variable and then logging it out,
we'll simply just console.log,
the "button" variable, and the "clicks" variable.
And we'll take this other variable out of here.
Then we'll also move the line
that sets the value of clicks[button],
and we'll move that within our inner function
after we assign a value to the "button" variable.
Because this statement has to be evaluated
when the report function, the inner function,
is called.
And then, we also need to move the parameter
from the outer function,
which we've been calling so far to the inner function,
which will effectively be calling when we return it.
I'm going to cut "menu" from updateClicks,
and I'm going to paste it in
as the parameter for reportClicks instead.
And then finally, we have to go down to the event listener,
which is in line 111,
and change updateClicks to "report" as the function to call
in response to a click on one of the buttons.
And we save and then reloading in the browser,
and we're going to test, is Omaha.
We have a forecast, and when we click buttons,
we get those same results.
We've done some pretty fancy code reorganization,
but without any particularly concrete results.
Switching back to the code,
there's one more thing we can do that's pretty useful.
We can move the "clicks" variable
into the updateClicks function.
Close up the spaces there.
Now, originally we kept that as a global variable,
so its state would persist
between each time the updateClicks function was called.
But now let's save and we'll reload in the browser,
test with Omaha, click some buttons.
And we still get the same behavior,
so that "clicks" value is persisting.
How is this working? Well, looking at our code,
the updateClicks function is returning the inner function,
reportClicks.
And reportClicks has its own scope
and also has access to the local variables
of its parent function, updateClicks.
Now, normally when a function returns,
it's done executing and all of its values,
including variables,
are garbage collected by the parser
and are no longer available.
But because updateClicks returns a reference
to an inner function that has access to its local variables,
when updateClicks returns,
its references are not resolved, they remain in memory.
And the reference to those variables
that we've returned from the function
in the form of the "report" function is called a closure.
One of the advantages of a closure,
which we can see right here in this code,
is that we've removed clicks from the global scope.
And that has a couple benefits,
one is just supporting the basic practice
of keeping variables out of the global scope
as much as possible.
If we were working with several different variables here,
instead of just one,
and we were able to move them all out of the global scope,
that would be a significant benefit.
And the other thing
is that even though our "clicks" variable
is still available to our app,
and we can work with its value,
it's available only through our closure,
through the "report" function.
And this means that it's somewhat protected.
If we're building out this code later,
or another developer is working on it,
we can't simply write code to change this variable
because only the "report" function has access to it.
Closures have concrete benefits to our code base
in terms of organization and protecting variables.