- [Instructor] The first building block
of closures is scope.
Scope is a way of describing which variables are available
in different contexts within an application.
JavaScript includes a few different types of scope.
For the purposes of creating a closure,
two types of scope are important, global and local.
The main difference between these two scopes is
whether a variable is created within a function or not.
Global scope describes the variables
that an application has access to anywhere in the code.
Global variables are created outside of functions or blocks
such as conditional statements or loops.
Global variables are most commonly declared
at the start of the code.
Any statement in a JavaScript application has access
to all of that apps' lobal variables.
In this code, the forecast variable is global
so we can reference it anywhere in the code,
including in the advise function.
Local variables on the other hand
are not available everywhere.
A local variable is created within a function
and is available only within that function.
Code outside of that function
cannot access the variables value
by referencing the variables name.
However, all global variables are available
within a function because as we saw earlier,
global variables are available absolutely everywhere
within an app.
For instance, in this code,
the forecast and tempC variables are created
in the global scope,
but the tempF variable is created
within the advise function.
So it has local scope within that function.
This means that the tempF variable is available only
within the advise function.
So if we tried to access it outside of the function,
like on this last line,
where we try to console.log(tempF)
outside of the advise function,
we would get an error because that locally scoped variable
is not available outside the function.
You can think of a function as similar to a one-way mirror.
Code within the function can see out
and access global variables,
but code outside the function sees only the mirror,
blocking any access to the variables declared inside.
The start files for this video are an app
for a sports product company.
When a user enters a city or other location,
the app looks up the local weather
and suggests whether appropriate sports for teams,
individuals, or all of these together.
Here in the script.js file, I want to add some new code.
Now that our app is live,
we want to collect some information on how it's used.
And we're going to start
by logging how many times a user clicks each of the buttons
for the three categories of sports.
Later on, we need to write some code to connect
to the backend and submit this information.
But for right now, we just want to capture it
and verify that it's being recorded correctly.
I've already added an event listener down here on line 97
for an update clicks function whenever a button is clicked.
So here at the top of the file,
I'll create a function called update clicks.
And this will take a single parameter
from the event listener,
which will be a reference to the click target
so we'll call it menu.
And within the function,
I'll start by adding a variable called clicks,
whose value is going to be an empty object.
Because this is in a function,
that clicks variable has local scope,
local to the update clicks function,
and it's not available outside of this function.
And then I'm going to create a variable called button
and set its value to menu.id,
which is the ID value of the element that was clicked.
This is going to be useful for us.
And then I'm going to set a new key value pair
in the clicks object using clicks[button] as the key
because those ID values correspond to the labels
of the buttons as well.
So they're ideal to use as keys in our object
to store clicks for each button.
And after the equal sign,
I'm going to set this two clicks[button] + 1.
But if that key doesn't exist yet, this will be undefined
and this math won't work.
So I'll add an or, || and 1
to set the value to one otherwise.
Now, before we test this out,
we have to make sure that we replace the placeholder here,
API key, with the actual API key value.
So over in my note, I'm going to copy my API key.
I'm going to paste that in here.
And I'll save my work.
And at the command line,
I am in the start files for video 01_01.
So I'm going to start my HTTP server.
I'm going to set it to port 3000.
And then in my browser,
I'm actually going to go to local host 3000
and I'll enter Boston in that box,
click the get forecast button, and we get the forecast.
And then I will click these buttons a few times.
So hopefully we'll log a few clicks in our object.
And then I'm going to open the console
and the fave icon didn't load, that's fine.
And I'm going to close this little update down here.
And then I want to check the value of that clicks object
that hopefully all those clicks have been being added to.
So I'll type that, and it says clicks is not defined.
So returning to our code,
let's think about why that might be.
So we already said that clicks is a local variable
to the update clicks function.
So because of that,
once the function returns at the very end,
the rest of my code doesn't have access
to the clicks variable.
So instead of trying to log that value from the global scope
in the console where I don't have access to it,
what if I instead add a console.log statement
within the function itself,
that way we know the variable exists
when the statement runs.
So before the end of the update clicks function,
I'll add a console.log and I will just log clicks.
And then I'll save my work.
I'll go back to the browser and I will reload.
And this time we'll enter Mumbai,
get the forecast and I click team,
and they're in the console,
I see my clicks value containing the key team
and a value of one.
So far so good.
Now I'll click solo
and I get another statement log to the console,
but now my object still has only one key, but it's solo.
And we find that no matter how many times we click,
we only ever see a key with a value of one
for the most recent click.
So what's going on now?
Well, going back to our code,
let's think about what's happening
in the update clicks function.
When we click a button, the function runs.
The clicks object is created.
A value is added to it.
It's logged to the console.
And then the function ends.
And when the function ends,
the local variable is no longer used by any code in our app.
So it no longer exists either.
So the next time the function runs,
the object is recreated with an empty value
and we start over again.
This is clearly not what we want.
We want a running tally.
Well, remember our two way mirror.
Code in a function can see out accessing global variables,
but code outside of function can't see in
to access local variables within the function.
So how could we use scope to fix our function here?
One way would be to move the clicks variable definition
outside of the update clicks function.
This means it stays around
even after the update clicks function has finished running,
but the code within the function
can still access this variable from the global scope.
So I'm going to cut and paste the let clicks statement
outside of the update clicks function.
And then I'm going to save my code.
I'm going to go back and reload my browser,
and I will enter a Mumbai again.
And now I click team and they get that log in my object
in the console.
Click solo and now that's added to the object
rather than replacing the existing object.
I click all and that's added as well.
And now when I click team again, the value updates to two.
So each new click is added to the ones
that were there before.
And that's because the variable is not deleted
after each time the function runs
and that's because the variable is outside the function
in the global scope.