Lesson Description

The "Closure Use Cases" Lesson is part of the full, JavaScript: The Hard Parts, v3 course featured in this preview video. Here's what you'd learn in this lesson:

Will explains several use cases for closures in JavaScript, highlighting its role in maintaining persistent memory within functions. These use cases include helper functions, memoization, iterators, generators, the module pattern, and asynchronous programming.

Preview

Transcript from the "Closure Use Cases" Lesson

[00:00:00]
>> Will Sentance: Closure gives our functions both. All functions get a memory when they get run. That's what goes in the execution context, a mini program with—you can go through the code and you can save stuff. You don't want it to remember the next time because I don't want to run multiply by 2 on 7, and then run it again on 10, and it's still got the memory of running it on 7, because it's like, it's still like a sort of reverie from—that's an old-fashioned reference to Westworld, which, but you don't want to have it have a sort of memory that it previously ran on 7, like vaguely there.

[00:00:33]
You want to start afresh. So it's fantastic that functions don't remember their previous invocations, get started again. That's a key part of their design, modularizing our code. However, if we can also give them a special store of persistent data, that is powerful, and it is a vital part of the toolkit for writing pro code. So for one, helper functions. These are ones that we use just every day, like want to memorize.

[00:00:59]
So the once function, you might oncify a multiply by 2, such that the first time it takes in 7, you go 14, great, but the next time it takes in 10, you say, sorry, I've already been run, because it checks in the counter in the backpack. Multiply by 2 is counter, maybe increments each time, and it checks, or you could even have a true and false, run before true, run before false, whatever, and it checks it and goes, ah, sorry, you've already run me before, can't run me again.

[00:01:36]
That's not the best use, but oncifying a function might be really useful. You might want to prevent a win function in a game running more than once, in order that the user can't accidentally win twice. Memoization, things like if you have a function, nth prime, that's going to take in, I don't know, 1.2 million, and try and calculate the 1.2 millionth prime number. 1.2 millionth prime number, that's going to have to do a lot of math.

[00:02:08]
I don't want the next time that somebody passes in the 1.2 millionth prime number to have to redo that math. So a standard practice in engineering is to memoize, to track as a pair of values, 1.2 million, with whatever the 1.2 millionth prime number is. Where can I store that in the nth prime number's, nth prime function's backpack? So that when I run with 1.2 million, the first time, I check the backpack, no 1.2 million.

[00:02:40]
I add it, do the work, store the result. Next time I pass 1.2 million, grab the result, return it straight out. All of this is using the backpack closure. Iterators and generators, they use the same concept to—particularly iterators to—and this is in the async hard parts, I think. I think it's in the async hard parts if you ever want to watch that. In those, and it's a longer form course from a few years ago, that dives into building out iterators and generators under the hood.

[00:03:13]
Iterators allow us to not look at a list of values and use the for loop to go through them, but instead have a function that when run, returns out the first time, the 0th element of the array, the next time, the next element of the array, the next time, the next. But a function doesn't remember the last time it was run, so it doesn't know what position it's in. Don't panic, it keeps track of it in its backpack.

[00:03:39]
Iterators are absolutely using closure under the hood. Generators are even more interesting. They say that you could pause the running of a function halfway through, potentially until some asynchronous work, maybe over a server or API call, gets back the result, then you can continue on. Well, what do you need to continue a function on? You need its local memory, you need the line position in the code.

[00:04:11]
I think that's it. Yeah, and so where's that stored? In closure, in the backpack, allowing us to literally pause or appear to pause a function and continue its work after some asynchronous work came back, because we hold onto our data in a closure and the position in the code in a closure. The module pattern, we already heard about this, the ability for us to not have to get upset with our colleague from 14 years ago who used results in global.

[00:04:39]
But instead, be confident that we can have—well, sorry, we can have persistent labels that don't pollute the global memory. Remember, you're like, well, why don't I just have it in a function? Because once that function execution context closes, that label's gone. So you have to have a way of having lifetime memories, but not in global. And the answer is in backpacks, and the module pattern absolutely depends solely on functions having persistent memories that we can then access by calling the functions.

[00:05:13]
And have a look at the JavaScript module pattern and play with, and it's in the challenges, how it implements it using the backpack, using closure, using functions having persistent memory. And finally, asynchronous JavaScript callbacks and promises, these are going to allow us to go and do work that takes time, particularly with API calls, particularly with speaking to the internet, the thing that makes JavaScript the most popular language is it's in the web browser.

[00:05:40]
When we get data back, we want to do stuff with it. We didn't go and get the latest Spotify tracks to not do—the latest screeds off Twitter, no, we didn't go back and get the latest, I don't know, Spotify—how about the latest viral videos, we didn't get them back to then not do something with them. We wanted to run some code on them. But some of the code we want to run may also involve other data besides the data we got back from the API call.

[00:06:07]
How can we have that data still available to us? Don't panic, the function we run will of course have a backpack of the data from when it was defined. Meaning when it gets called, that data is still available, even if it's running at that point in global.

Learn Straight from the Experts Who Shape the Modern Web

  • 250+
    In-depth Courses
  • Industry Leading Experts
  • 24
    Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now