Check out a free preview of the full The Hard Parts of Functional JavaScript course

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

Will demonstrates how closure allows the storing of a function's memory by executing that given function within another function.

Preview
Close

Transcript from the "Closure" Lesson

[00:00:03]
>> Will Sentance: But it all relates to what our dear friend Seth kindly brought up, which is, my dream to be able to list off my lines of code, by name and say, you go now run them one by one and take the input 11 for the first one. And have its output of that first line only be affecting only locked into only affecting by the very nature of reduce only be affected in the next nine out of three, whose cords was only affects the next time, we got it.

[00:00:37]
I'm not the and by the way, given his only effect is the next line there's no need for me to state arguments. I'm gonna auto run that function under the hood through the help reduce. Problem is, I'm therefore gonna have no control over the inputs I pass the function.

[00:00:54]
For example, that add three function I've got a problem if that add three function expects two inputs. Suppose I hadn't added to numbers function is going to be a big problem. Well, we're gonna discover this sort of second half, we're gonna solve that. But to do so, we wanna think firstly, if we're building applications centered around little baby functions is that cool unit.

[00:01:21]
From which we build up our applications. My goodness, what if we could give them a superpower? What if we could make them as powerful as possible? And closure is gonna do that for us. And it's gonna be vital for later on enabling us to success problem that he raised,that holder if I'm listening or functions, and one of them expects two inputs, and I've only got one of them, only one input the output of the previous line, how can I adjust that function?

[00:01:51]
When it's gonna turn out, I'm gonna prefill that function, I'm gonna need that function, to have some sort of little persistent memory data store attached to it, into which I can store the other input of that function, so that it only actually needs one to run. But it's gonna rely all on closure.

[00:02:12]
So here we go. The most esoteric concept in JavaScript in my opinion, although having seen reduce, I don't know. Functions are our units to build but they're limited. Every time they run they forget their previous running. Now especially with no global states that's not a great thing that every single time they run they forget the previous anything about the previous time they ran.

[00:02:37]
Imagine if we could give our functions memories, permanent memories. The things we could do. And I do want somebody to raise a challenge with this through the functional programming lens at some point, and I'll give you some thoughts on that. But for now, let's remind ourselves exactly how functions actually work.

[00:02:55]
Go to function, move over to here. That's right. Once again, I want to do it because I want you all to just get ourselves back in the flow. MultiplyBy2 is a function here. When I run it with the input of 7 my parameter, what's my parameter here for multiplyBy2, Alex?

[00:03:11]
>> Alex: Input number.
>> Will Sentance: Input number is filled in with what?
>> Alex: 7.
>> Will Sentance: 7, perfect, and 7 by 2 is returned out 14 to output. When I run multiplyBy2 again, this time I'm going to input a 3. Does it have any memory that it was previously run with seven?

[00:03:26]
Absolutely not that easy, why wasn't worth writing direct result? I think we got that one. No memory, the previous execution. Imagine if we could give our functions permanent memories. Now this may, this may [LAUGH] sound on is this I'm doing some volunteer work well we're going to talk about that.

[00:03:45]
But for now, let's imagine we give out functions permanent memories such that they remember things about their previous invocation. Previous runnings, but it all begins with returning a function from a function. Now, if you've been to close your heart, raise your hand if you've ever been to the closure hoppers you've watched.

[00:04:00]
Close your heart. Yeah, okay. Then we've seen this before. We're gonna use it to achieve some really powerful functional promo techniques. We do need to start it off. And this little thing here, it all begins with returning a function from a function. Maybe we're now so in the head of functions being little things bundled up we can pass around that we're gonna find this okay.

[00:04:18]
But know that the next page of code I've done in front of, these fancy engineering organisations and seeing senior engineers not really have precisely down what's happening here. So let's see that for ourselves and build it out. We're going to save a function, we're going to call it function creator, no inputs, we're going to then run it and still whatever his output is.

[00:04:41]
Intergenerational funk, we run it one time, right multiple times and arts. We're definitely not storing function creator in a generation funk. We're instead gonna run function creator, whatever it returns out which probably people are already starting to guess that's gonna be generated fun. And then the very next line, we're going to run.

[00:05:03]
Well, hopefully whatever we got out of jury the funk is a function as well. We're gonna use generated funk as a new label for that function that came out of function creator. I wanna stress to you that even seasoned engineers look at this code all the time they go generated fun what's generated fun invited to all its function creator.

[00:05:26]
All right, so I throw two in the function creator. No, no, no, no, no, no, no. Raise your hand if you think well, I don't know. Raise your hand if you've ever instinctively maybe thought that's what's happening here. Yeah, a few of us, right? I wouldn't be surprised, I absolutely have seen I'm talking seasoned engineers, I'm talking engineers with ten years experience, who kind of get confused about this.

[00:05:48]
No, we're gonna see this as a one-time running of function creator, save whatever comes out of it in generated fun, and then never care about function creator every again unless we use it again. And generatedFunc is now whatever came out of function creator. Which presumably is a function of free, but let's go through this line by line and understand it incompletion.

[00:06:05]
Alex, line one, what are we saving?
>> Alex: Clearing function label function creator.
>> Will Sentance: Excellent, there it is. No different than normal. Saving it into global memory function creates its own function. People were almost there. Slash not. All right, next line, Anna left hand side of next line.
>> Anna: Declaring a function called generatedFunc.

[00:06:35]
>> Will Sentance: I wouldn't say that, declaring a label generated funk into which will be stored what Ana?
>> Anna: The function creator?
>> Will Sentance: Is she right? She's spot on, exactly! The output, the executed, no, that's not right, the return value of executing function creator is running it. And, Anna, what told you that, what symbols told you that that right-hand side was work to be done?

[00:07:08]
>> Anna: The parenthesis.
>> Will Sentance: The parenthesis, exactly. It's a thousand times people have found this single line one of the hardest, it's the biggest gotcha in Java. It's not really a gotcha, a gotchas like more of a trick, it's more like just, we really need to understand what we're doing when we run functions.

[00:07:25]
What we're doing when we say functions. What we're doing when we declare labels, to know what's happening in this line. Okay, there it is, generatedFunc. For now, it's uninitialized. I was gonna tell you why. Why we say uninitialized on defined was what would happen when you declared you will label that was gonna be the output of the function on the right hand side with valve.

[00:07:48]
Then with the fault one fine, one find while the function ran and then you would redefine it as a result of the function call. With a const declaration, you can't have two data types changed out. You can't declare it is undefined initially. Default is one to find and then when you get the result of the function call, suddenly switch it out to whatever the result of the function call is.

[00:08:07]
So instead, you don't even actually fully declare the label generatedFunc until you've actually got the result of the right hand side running. This relates back to Charles's question much earlier, about undefined versus uninitialized, generated func declared, what do we need honor to go and execute to figure out what to store in generated func?

[00:08:31]
What do we need to go and execute to figure out what to store into generated func?
>> Anna: Function creator.
>> Will Sentance: Function creator, let's get executing. All right, so we're gonna execute functionCreator. Anna, we need a new what?
>> Anna: Execution context.
>> Will Sentance: Excellent.
>> Anna: [LAUGH]
>> Will Sentance: And we know that whatever comes out of it, is going to be stored into generatedFunc.

[00:08:59]
Let's create our execution context, there it is. And [LAUGH] it's a rhombus at this point. And Charles into it we go line one. What are we gonna do? We're not gonna use this thing I just want you to show, I just want to make sure everyone knows we're saving stuff into memory.

[00:09:21]
What's the first thing we save into memory?
>> Charles: Counter.
>> Will Sentance: Counter is zero.
>> Charles: Counter is zero.
>> Will Sentance: Exactly. Okay, I'm gonna do my call stack as well actually for this one, it turns out to be increasingly important to think in terms of it to not get confused.

[00:09:37]
All right? And first thing on it will always global, but what are we adding to it, Michael?
>> Michael: Add three. Function creator.
>> Will Sentance: Function creator because we're calling what function right now Michael?
>> Michael: We're calling function creator.
>> Will Sentance: Function creator. So we're going to add it to the call stack because our execution context in action right now is function creator's.

[00:10:03]
Our thread of execution has woven into function creator. That's where we are right now, it's top of our call stack, okay? David, we've saved counter is zero inside the local memory. David, next line what's it say to do?
>> David: We're declaring a function with the label at three.

[00:10:22]
>> Will Sentance: At three, there is, there it is. Okay are we gonna use it David?
>> David: Not right now.
>> Will Sentance: No what are we gonna do with it instead?
>> David: We're gonna return it.
>> Will Sentance: Exactly i'm gonna write that here return at three. Anybody wanna tell me therefore what Javascript actually does in that return statement?

[00:10:44]
Jasmine you wanna tell me what Javascript does in that return statement return at three?
>> Jasmine: It replaces at three with a function.
>> Will Sentance: You hear this? Exactly. It looks at the function definition using that label and it grabs the function definition, which is the bit in the parentheses nom and then the body of it it grabs all that and it returns it out of the cool to function creator and stores it Jasmine where?

[00:11:10]
>> Jasmine: In generated func.
>> Will Sentance: Into generated func. She is spot on. Into generated func, it goes. It was formerly known as its birth name was add three. But now we returned out all the code, grabbed it all, shot it out the bottom no name. We lost that name.

[00:11:33]
We just returned that we just use it to look up the function as Jasmine said, and it got stored into generated func. If I were to now console log generated func, I would see input num body, whatever it says cons result equals num plus three return, that is now generated func, that is what it means to return a function.

[00:11:55]
From another function. Let's now, so this is now popped off the cool stack and all this goodies here. Well, in theory, the execution context is gone. The execution context is all deleted. And
>> Will Sentance: Look at that, that's rather nice. And we go back out to global where we hit what line, Sam left hand side?

[00:12:26]
>> Sam: Result.
>> Will Sentance: Result, and the right hand side says go run what function Sam?
>> Sam: Generated func.
>> Will Sentance: Go run generated func. And what was generated func's original name, Sam?
>> Sam: Function creator.
>> Will Sentance: Aaah. It's so easy to think it right? What is generated func?
>> Sam: Add three.

[00:12:51]
>> Will Sentance: Folk with literally 10, 15 years experiences, and enormous gifts in engineering, still get caught by this every single time and yet if we don't get it absolutely precise in our head everything falls apart in understanding what's the conclusion. 1,000 times. I've really stressed for you, Sam is in the company of I'm literally talking about like the rock stone, I don't want to use that silly term, the superstar developer, she's the person that to all so every single time this throws people.

[00:13:24]
We've got to go run that function one time, store something in generated func it is the functionality of add three. And from that line on generated func is the code formerly known as add three. Thank you, Sam Hollasey because everybody is going, yeah I felt the same thing.

[00:13:43]
Appreciate that from Sam. So generated fund Jasmine is the function that was born as
>> Jasmine: As add three?
>> Will Sentance: As add three. The function definition formerly known as add three now known as generated func its global label that was its label inside a function created when it was originally saved just like we save count from side of that.

[00:14:04]
But we grabbed its code, we only used, when it says return add three. We only used that label to find the code of the function. Returned it out stored in generated func. You only think, some of you maybe think, I got this. I promise you people it is a real toughy out it comes generated func is really David the code formerly known as?

[00:14:22]
>> David: Add three.
>> Will Sentance: Add three meaning after I leave function creator inside of which add three was saved I can't call it, I can't reference add three anymore it's gone. Unless I say it in a new global label, David what was that new global label I saved add three in.

[00:14:38]
>> David: Generated func.
>> Will Sentance: Generated func, so when I run generated func I'm really running what Eric?
>> Eric: Add three.
>> Will Sentance: Add three. So if I want to refer to add three out in global, what's his new name? Andrew?
>> Andrew: Generated func.
>> Will Sentance: Is generated func actually function creator, Andrew?

[00:14:54]
>> Andrew: No.
>> Will Sentance: No, what would I need to change Andrew in order to make generated func act as a new label for the whole function creative code. What would I need to change in that line, so that the generated func is actually just a label for all of function creator?

[00:15:10]
>> Andrew: Remove the parentheses, right?
>> Will Sentance: Remove the parentheses. Spot on very nice from Andrew. All right, but it is a the output of a one time running or function created which actually we've got it I don't know if we have by the way I promise you this is super tricky this bit.

[00:15:23]
So let's run generated func new execution context. There it is let's put it on the cool stack. Sorry everybody. I do apologize, we are executing generatedfunc, we need a brand new?
>> Alex: Execution. [CROSSTALK].
>> Will Sentance: Execution code as well. Excellent generated func for all we know is add three, no, yes add three?

[00:15:48]
With the input of sorry, two, I've done this so many times with a different function that I can't get my head out of it with the input of two sorry vote. There it is, the input of two, there we go. A generatedFunc input of two. Now, here's the especially tricky bit in my opinion of all this.

[00:16:08]
Here's the especially tricky bit of it all, is in order for me as a developer to figure out what generatedFunc is doing, where do I take my eye Alex in order to figure out what generatedFunc is doing?
>> Alex: You look at whatever was returned from functionCreator(). Well, that's a very sophisticated way of putting it.

[00:16:25]
>> Will Sentance: Yes, but actually my eye goes back up to add3, right, like I have to. And so we get this false sense that JavaScript's thread goes back up into functionCreator(). It definitely does not, and huge shout out to Alex for stressing that, by saying actually, it goes and looks what was saved, in generatedFunc.

[00:16:47]
Which was the definition of code of add3. In fact, this f just represents the code of add3 being saved now in global, there ain't no going back into functionCreator(). That's done, that's gone. Instead we're going and looking at the code written here, which was roughly num and then return out numb+3, roughly.

[00:17:09]
That's where we go and look, yeah, go ahead, Virginia.
>> Virginia: Just a quick question. So when you say return add3, you're saying, it is it doing a literal copy of add3 there?
>> Will Sentance: Okay.
>> Virginia: So that when I go and say, like I say, generateFunc(2) is equal to add3, so those two different copies in memory of that function A-

[00:17:28]
>> Will Sentance: GeneratedFunc-
>> Virginia: So say go back and say, generateFunc(2) equals two function generator.
>> Will Sentance: FunctionCreator() being-
>> Virginia: That same-
>> Will Sentance: Even though never being?
>> Will Sentance: Do you see how important it is to get that technical communication right? So let's go into Virginia's question just a second once you got through this, but I want you to think Virginia before we ask the question, you said, if I went back and wrote generatedFunc(2) is equal to functionCreator().

[00:17:54]
>> Virginia: Well calling functionCreator().
>> Will Sentance: So important, we'll come back to the question in a second Virginia, I promise but just yeah, we'll come back to the question in one second, I promise Virginia. But for now, let's stay in generatedFunc. We're running it, everyone together, generatedFunc is the function definition that was originally known when it was inside of functionCreator() as-

[00:18:15]
>> Virginia: Add3.
>> Will Sentance: Yeah, good, exactly. And [LAUGH] so, into it we go. And, who said function multiplied by two? That was a good throwback reference if someone said that. All right, into it we go. And unfortunately, although we don't have to, we can go look here. What's the parameter to which the two is gonna be assigned Michael?

[00:18:38]
>> Michael: Num.
>> Will Sentance: Num, raise your hand if you looked back into functionCreator() to figure that out. Well of course we all did, we can't memorize all functions coming out. But I wish we could sort of see in console log generatedFunc in that middle, in between those two lines, we should almost restrict ourselves, make ourselves console log generatedFunc to figure out what the code is we're running down there.

[00:18:59]
So that we don't think of going back into our code where we initially saved it because it ain't in there, we don't get to thread back into that. Okay, but all right, num is two, let me do result which is 2+3 which is 5 and then we return the value result in 2.

[00:19:18]
Why did I call them both results? Dear, I thought I changed that. Return the value result, everybody, into what global constant also called?
>> Alex: Results.
>> Will Sentance: That's bad explanation by me, I apologize. Note these are in different domains and so they're not gonna override each other, okay.
>> Will Sentance: What was I gonna ask?

[00:19:44]
That's what I was gonna say. We're gonna come to thumbs where Virginia is gonna raise her question. Thumbs on in a moment. We saved code functionCreator(). There it is. We then saved a label generatedFunc for whatever came from a one time running of functionCreator(). There's the params to say, go run functionCreator().

[00:20:08]
Into we went, we created a brand new function add3 and then rather than using it, we returned out its code and stored it under a new label generatedFunc. And from then on forevermore, generatedFunc cares nothing about functionCreator(). It only cares about the add3 function that's now stored in it.

[00:20:30]
So we ran it and we ran generatedFunc and it's just add3. We can just do it. It feels weird but we didn't put prands on the end, no problem. No problem. And it's running add3, I'll put two into it, and it goes num is two. Result is 2 plus 3 is 5.

[00:20:46]
Return our result into global constant result. Okay, folk, you might be thinking why the hell did we do this? Why the hell did we save a function we could have declared globally inside another? Well, we'll see that gives our functions the biggest superpower in JavaScript.

Learn Straight from the Experts Who Shape the Modern Web

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