
Lesson Description
The "Closure Overview" Lesson is part of the full, Functional JavaScript First Steps, v2 course featured in this preview video. Here's what you'd learn in this lesson:
Anjana introduces closure, which is the combination of a function bundled together with references to its surrounding scope. Closures are created every time a function is created, and the function "remembers" its outer scope. This lesson also explains additional terms like partially applied functions and currying.
Transcript from the "Closure Overview" Lesson
[00:00:00]
>> Anjana Vakil: Time to talk about another class of functions, let's say that is hugely useful, if not indispensable, to functional programming. And this also has to do with how we remember things that in our imperative life we were used to doing with state. We were used to remembering, like what the state of the program is at any moment with variables that the values change over time.
[00:00:23]
And we just said that in implementing our reducer functions, we use an accumulator instead. In functional programming, we use a value to remember kind of where we're at in our repetition, another way that we can remember things to use them later is closure. So that is our next topic of discussion.
[00:00:47]
So, closure is not just something that's hard to find after a breakup, it's also [LAUGH] a very useful concept that has to do with the scope in functions.
>> Anjana Vakil: So in addition to functions being able to be higher order in the sense that they take in another function like filter, map, and reduce do, we can also define a new function within a function.
[00:01:18]
Let's take a look, [LAUGH] what I'm talking about. So this is when we have these kind of nested function definitions, this is, I'm using the function keyword, but you also might see this with arrow functions. Although we're not so much gonna be defining new functions and arrow functions.
[00:01:35]
Okay, so in this case I have a function called makeAjectifier, [LAUGH] which returns another function. And makeAdjectifier takes in an adjective, and the function that it returns uses that adjective to objectify whatever noun I'm gonna pass in to the adjectifier that I made. [LAUGH] Okay, so let's say I'm gonna assign, I'm gonna call makeAdjectifier with the word cool, and that's gonna give me a function called coolify.
[00:02:10]
And so, if I want to coolify a workshop, I get cool workshop. If I want to coolify a drink, I get cool drink. But notice that the word cool is not part of my calls to coolify, why is that? Well, because it is sort of baked in to coolify.
[00:02:32]
Essentially, what we're doing here, when we create this new function inside an adjective is just a value here as far as JavaScript is concerned. And when we define this function, we know what that value is because we're calling makeAdjectifier. So JavaScript takes that value, which is only available in the scope of makeAdjectifier, and uses it inside the returned function.
[00:03:03]
>> Anjana Vakil: So when I actually get out this returned function, it still has that value baked into its code.
>> Anjana Vakil: In other words, it remembers the value from the scope in which it was defined even after we as programmers have left that scope. The function is sort of locked in to that scope, the inner function, in the sense that it has access to that adjective only at the time that it's defined, like, what is the adjective?
[00:03:39]
Well, that happens at definition, it's cool. And then forever and ever now, coolify is gonna make everything cool, not hot, unfortunately, for northern climates in northern hemisphere winter. [LAUGH] All right, so this is a very simple example, but this is a super powerful concept. What this means is that, we don't have to take every single little piece of data that we need to do computation and make it part of the function signature, cuz that would get very unwieldy very fast.
[00:04:14]
We can also do techniques like closures, where we say this inner function is closed over adjective because adjective is sort of set in stone now. The opportunity to change adjective has closed, and so, these closures can become very powerful when we start needing to have more and more complex computations.
[00:04:41]
We can start baking those in to inner functions and creating closures that we can then remember the value as needed. Let's take a moment to talk about a little jargon. So we said a closure is one of these kind of inner functions that closes over some value from its defining scope.
[00:05:05]
And another way of or another term you'll hear used to talk about doing something like coolify here is partial application. So closures are a type of partial application of functions. And I'm only using this term, not because the jargon is important, but because you might encounter it in your further learnings and readings.
[00:05:32]
And what this means is, if we have a function that takes two arguments, in general, if I wanted to take in an adjective, and take in a noun, and smoosh them together, I would need two arguments. We're kinda locking in one of those arguments, in this case, adjective and splitting up the scope of where adjective is passed in.
[00:05:59]
It's passed in to make ejectifier, which is sort of a partial application of like adjective plus noun. So coolify is like half done with this. It still doesn't know what the noun is, but it knows what the adjective is gonna be. So we could say that, if I had a function that was just like function, adjective noun returns adjective plus noun, we would say this is like a partial application.
[00:06:26]
It's one of the arguments has been locked in, but not all of them. Anyway, just a little jargon note. And so, the idea is that this means we can make more reusable functions. So for example, every time I want a cool workshop, or a cool drink, or cool movie, or whatever, I don't have to keep passing in cool over and over.
[00:06:47]
I can lock it in and have a partially applied adjective plus noun function called coolify, which then I can just finish out the application by passing in that next thing or in case of multi-argument functions, whatever other values I need. Okay, so, there is another concept that we're not gonna have time to cover, that you might also run into here.
[00:07:16]
But there is a jargon term called currying and essentially what this means is, it's a very common practice in functional programming to take a function that could ostensibly have two arguments, right? Like, maybe I had a function that's just like adjective, fine noun that says, give me the adjective, give me the noun, and I will return the concatenation.
[00:07:42]
That wouldn't be a super, or it would just be really annoying to have to keep passing in cool every time. And so, instead what we've done is, we've essentially taken what would have been a two-argument function and we've turned it into a nested series of one-argument functions. And that is a technique called currying, which basically means you have a partial application where each function takes in the next argument and returns the partially applied function.
[00:08:12]
Which then takes in the next argument and returns the partially applied function. Anyway, this is just a way of saying that sometimes, instead of working with a multi-argument signature, we might wanna break that up into partially applied functions so that we can lock in some of those values.
[00:08:30]
So that we don't have to keep repeating our self over and over again, because you know me, I'm gonna make a typo in one of those cools, it's gonna be like, cowl, or, cool, or something like that. So, we don't wanna be doing that, I just wanna type cool one time and never have to worry about it again.
[00:08:47]
And currying is a technique that often goes hand-in-hand with closures. It's sort of a it leverages closures. So anyway, this is a term that you encounter. You can deep dive into it, but this is something that is very closely related to this idea of partial application. So in currying, what we would do like, yeah, here's another example of a similar type of function.
[00:09:13]
We have a greet function that we saw earlier that takes in a greeting and a name. And if we wanna curry that function, meaning turn it into, instead of a single binary function, meaning a function with a two-argument signature. We will partially apply [LAUGH] just the greeting and return a new function that takes in a name, and that function is what's gonna return the final output.
[00:09:39]
So then, it's starts to get a little bit more weird looking once you get into many, many different arguments. Because you'll start to see things like curryGreet, howdy, open parens, Alonzo, like these kind of successive paren, paren, paren. So if you see code like that that's like, take this thing in parens and then call it on this thing in parens, and then call it on this thing parens, you're probably dealing with closures.
[00:10:10]
It might be a curried function. So anyway, so this is the idea that often it's useful to break up function signatures like this so that we can create these reusable utilities. Now, this is probably not one you're gonna need anytime soon in your JavaScript journey. But there are lots of other cases where we wanna be able to reuse the same value over and over again in our code without having to pass it in as an argument to every single call to every single function.
[00:10:39]
So scope is what it's all about, and the notion of closure, meaning the notion that we can lock in the outer scope into the inner scope. Is what's gonna allow us to make more modular functional programs that we can reuse and recombine as need be. And we will talk about the combining part later.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops