x is a global variable so its viewable both outside of and inside
y is local only to
logXY() and is therefore only available inside
Now let’s adjust the scenario above as follows:
If you are used to programming languages like Java or C++, the variable
x, for example, is local only to
setup(). So once
setup() finishes executing its no longer needed and goes away! So when
logAgain() is called later in
mousePressed(), there should be nothing storing a reference to
x and the result should be
But it’s not!
y’s scope are limited to
setup(), they also extend beyond
setup() to anytime that
logXY() function is called.
This idea of keeping scope for “later” is crucial for callbacks and becomes relevant for scenarios like animation and API callbacks. Let’s look at animation first.
Let’s say you have a DOM element.
And let’s say you want to use
setInterval() to change the element’s count every N millseconds.
Now let’s say you wanted to do the same for more than one paragraph, and have the second paragraph keep its own “count”. Sure you could create
count2 and call
setInterval() twice. But better yet, you could use a closure!
Closures are also helpful when querying APIs. Let’s say for example, you have several DOM elements, each associated with a particular term. And whenever you click on any of the elements, you can to make an API call with the associated term.
Now the idea here is that the
queryAPI function would connect to the API itself.
Ooops! There’s no reference to the particular word associated with the element that was clicked on. (While yes, there are ways to get access to that word from the DOM element itself for the purpose of demonstrating the closure I’ll skip that as an option.)
Here what you may be thinking the following: “I want to pass an argument to
queryAPI. In other words, you want to execute the callback
queryAPI with the value stored in
words[i]. But you can’t. That is, unless you use a closure!
Here, the technique is to instead call a function where the callback is defined as a closure that maintains a reference to the particular term associated with the callback. In other words;
And then the
assignQuery pairs the value in
words[i] with the
mousePressed event for the DOM element.
gotData() function is also defined inside
assignQuery() then it can also make use of the closure maintaining a reference to the DOM element and associated word.
Again, the key here is that while the scope of
word is defined locally to
assignQuery, event though
queryAPI may happen later whenever the user clicks the mouse, long after
assignQuery was executed, that scope is maintained by the
queryAPI’s closure which maintains a reference to all variables within its own scope.
Here is the a full example that queries wordnik and returns substitutes a “related” in the DOM element. And the source code. The example also uses the “animation” closure to count while waiting for data back from the API.
Use a closure to create 100 DOM elements with
setTimeout(). Here is code that doesn’t make use of a closure and does not work properly.
Use a closure to animate a DOM element in some way with the
style() function. (Fill in the blanks).
Then assign the function to a single element:
Then start animating elements only once you click on them:
Now make many elements, each that start animating when you click on them. Do you need a closure now that you are looping through the elements? (Hint: yes, you do except for the fact the p5.js will assign the
this keyword to the element in a
Finally, can you get your
animate() function to return a reference to the interval so that you can start and stop the animation when you click on it? This one is hard!
Use a closure to make an API call to openweathermap.org. Send openweathermap a zip code and when the weather is returned, create a DOM element with that zip code and the weather data. Here is some code to help you get started.
Now can you make this work with multiple zip codes? Can you make buttons for each zip code that when you click on each button an API call is made for a particular zip code?