The Hard Parts of Asynchronous JavaScript

Return Function Inside a Function

Will Sentance

Will Sentance

Codesmith
The Hard Parts of Asynchronous JavaScript

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

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

After Will reviews iterators as a way to automate the accessing each element and be able to focus on what to do for each element, he illustrates how to functions can be returned from other functions with JavaScript.

Preview
Close

Transcript from the "Return Function Inside a Function" Lesson

[00:00:03]
>> Will Sentance: Now, we move on to iterators. Okay, iterators. Iterators,
>> Will Sentance: I said in the very start, that when we run or we write and run code, what we're typically doing is taking data, storing it, and then functionality, that we then apply to that data. Even as simple as I have a score for a player and I increase that score.

[00:00:31]
Functionality onto data. We call our live data that's stored in our application our state. That just means the labels and the data, the values currently in our application at that moment. But that kinda masks the small part that's actually pretty significant a lot of time. Which is I have my data, I have my functionality, but often my data is a collection of data.

[00:00:54]
Maybe an array, a list of data or a set of data, or a map of data. Or a object containing a bunch of properties with data. It's really a single element. So actually the process of accessing each of our elements from a collection of data is in itself a task.

[00:01:10]
The data is just not there which we can apply functionality to, we have to go access that data. And in arrays, we do it using indexes to grab the individual element. You sort of have a static collection of data, and go and grab an element, grab it. And actually, that's not a small process in its own right.

[00:01:32]
And we'll see, we'll play that out here with a for loop. And we'll discover that actually, it's not the most, I think, a beautifully designed process. It's not clear that that's the best unless it's, most of the time when I'm accessing my data, I know I just want my element, and I want the next element, and I want the next element.

[00:01:52]
I don't really care about how I go about getting those elements. So wouldn't it be amazing if we could rethink collections of data as instead a sort of stream of elements coming towards me, that I could call a function, I could run a function, that's just gonna instantly return me the next element from my stream, my flow of data?

[00:02:15]
So I would run a function, it would return out the next element for my flow. I'd run it, it would return out the next element of my flow. Rethink my data, not as a static collection, I've gotta go and manually get each element in order to run functionality on it.

[00:02:29]
But instead flip it and say, my data's there and I'm actually gonna have access to it by running a function which kinda turns on the flow of the next element of my data. And that is a paradigm shift in how we think about applying functionality to our data.

[00:02:44]
No longer is there the intermediate step of getting the elements, manually going into the data collection and grabbing the next element. That's not a small thing. And it's an unnecessary step when most of the time all I want is my next element in order. So why not instead rethink my processes being applying functionality to data as the data being given to me element by element from a sort of flow of that data?

[00:03:11]
Before we see that beautiful new way of thinking about our collections of data and getting them so we can apply functionality to them, or getting them element by element one by one. Before we do that, we're gonna see the old version, where we have a list of data, and we're gonna manually go and grab each element.

[00:03:28]
We're gonna discover, I said, a beautiful new way of thinking about this, using each element one by one. But let's first see. And by the way, it's gonna show us just how kind of imperative, procedural, bit by bit, kind of exactly how we're gonna do this, this old fashion method is.

[00:03:45]
Gives us really manual, fine-grain control, but at the expense of a clean, readable code. And also, I think a cleaner way for ourselves of thinking of our data as these flows of data, rather than static collections that we go and grab element by element. So let's first just at least see this traditional way.

[00:04:05]
And I think it's gonna show us we want a better way. But here's our traditional way. And I'm gonna try and diagram this. But part of the point to say is that for loops, diagramming for loops is an odd thing to do, honestly. When we think about most of our code, we run execution context to run functionality.

[00:04:28]
But our for loops are these funny little things that happen kind of in isolation of our regular way of thinking about code. But there we go, all right. Line one.
>> Will Sentance: James, what are we doing?
>> James: [COUGH] You're declaring a constant of numbers.
>> Will Sentance: Numbers.
>> James: And assigning it a new array containing the values 4, 5, 6.

[00:04:55]
>> Will Sentance: Excellent, James, spot on.
>> Will Sentance: Now, here comes my favorite bit, diagramming for loops. All right, here we go. Check this, do this. Okay, you can already see why these are problematic, but check this. So what's the check we're gonna do, is i less than numbers.length, okay. Is i, which is initiated to 0, less than numbers.length, which is 3.

[00:05:31]
Okay, which is 3 as is less, it is. And therefore, do this, which is console.log(numbers[i]). And then i++. That's our for loop try to be written up in a slightly more logical sense than the kind of weird, check this, do the code, come back, do this, check this, a weird circular flow of an actual for loop.

[00:06:06]
Okay, so i is less than 3, so we are now gonna do this. What is numbers at this point, Michelle?
>> Michelle: So numbers is the array 4, 5, 6.
>> Will Sentance: Yeah, and what is i at this point?
>> Michelle: i is 0.
>> Will Sentance: 0, already, I'm liking to hear the hesitation.

[00:06:22]
That's enough to tell us there might be a nicer way. So position 0 of numbers is, Michelle?
>> Michelle: [LAUGH] 4.
>> Will Sentance: 4, excellent.
>> Michelle: I can tell there's 4.
>> Will Sentance: Next thing to do is i++ with an increment i to 1, is 1 less than 3, yes, it is.

[00:06:39]
So we come back down here. Now, we get to position 1 of numbers which is?
>> Michelle: 5.
>> Will Sentance: 5, good. 5 plus what? Increment it to 2, 2 less than 3, yes, we come back down here. Now, i is what, Victor?
>> Victor: It will be 6.
>> Will Sentance: So-

[00:07:00]
>> Victor: I'm sorry.
>> Will Sentance: Perfect, thank you.
>> multiple: [LAUGH]
>> Will Sentance: You see, thank you, Victor. i is-
>> Victor: 2.
>> Will Sentance: 2, so number in position 2 is-
>> Victor: 6.
>> Will Sentance: 6. So we console.log 6, i++ 3, is 3 less than 3? No, it's not. So we come out of our for loop.

[00:07:19]
Okay, this is the best you can diagram a for loop, I think, honestly, in the conditions, and still,
>> Will Sentance: Thank goodness, we didn't make that mistake, thank you, ma'am. Cuz we're so busy figuring out how to access, that we can't focus on what we wanna do. And by the way, we're gonna discover, if we rethink our collections of data, our flows of data, where we grab element by element, we can dynamically control those flows of data.

[00:07:47]
We can set what our next element in our flow of data's gonna look like based on things that have happened in previous elements after they've been returned out. Rethinking our collections of data as instead flows of elements we wanna grab one by one, It's gonna give us control over what those next elements will be.

[00:08:06]
We'll see that a little bit later on, really, really cool. But for now, programs store data and apply functionality to it. There are two parts to applying functionality to collections of data, 1, the process of accessing each element, and then, 2, what we want to do to each element.

[00:08:23]
Iterators, this new way of thinking about accessing data from collections of data. I mean, it's like lists, or arrays, or whatever, automate the accessing of the element. So we can focus on what we do to each element, and make it available in a super smooth way. They make it available so they say we've got a function that when called with parens, returns out my next element.

[00:08:44]
Run it again, gives me the next element. Run it again, gives me the next. In other words, the function attached and bundled on it somehow, in the background must be our underlying collection of data. Plus also, we must somehow hold on to the information of which element am I currently at, so that we don't give me out the same element each time, but give me out instead the next element.

[00:09:08]
But we know that when a function runs it never remembers its previous running. Its local memory gets reset every time, right? It's empty, it's fill it, so how the hell am I going to have my function both be able to be run, give me the next element, but also therefore have underlying in it somehow bundled on it my underlying array of data that it's grabbing the next element from one by one?

[00:09:31]
And bundled on it the sort of tracking variable that's tracking which element have I already given out so I know which one to give out next, how am I gonna bundle that all up? Imagine, though, if we could create a function that stored the numbers, and each time we ran the function it would return out our next element from numbers.

[00:09:52]
Note you'd have to remember which element was next up somehow. That means between the function's invocations, runnings, it would somehow have to remember that what was the last element that was passed out, hmm. But if we could do it, this would let us think of our array, our list, 4, 5, 6, as a stream, a flow of data, with our function returning out the next element, and then the next element, did everyone get this bit yet?

[00:10:17]
And the next element, did I say this enough times? This makes our code more readable, and we'll see in a minute, more functional. But it all starts with us returning a function from another function. Because all the most beautiful, elegant things in JavaScript begin with us returning a function for another function.

[00:10:36]
Cuz that's gonna give our function that's returned out superpowers. My favorite feature inJavaScript is going to be revealed right now. But folk, also I'm gonna stress to you, do not get complacent about what this code is doing. This code throws the most seasoned engineers unless we're super precise line by line, and remember that we never return to previous lines of code.

[00:11:04]
We always finish a line of code, we're done with it. We store whatever was the result of the right-hand side in memory, and we move on. So I want to start off by saying. Okay, so line one, Blessing, what are we doing in line one?
>> Blessing: We're defining a function, createNewFunction.

[00:11:24]
>> Will Sentance: Excellent.
>> Blessing: [INAUDIBLE] equivalent memory.
>> Will Sentance: Excellent, excellent, very clear, createNewFunction. Mm-hm, not quite the right casing. There you go, createNewFunction stored in global memory. Next line up, Josh? So we grab the whole createNewFunction, store it in memory, what's that next line?
>> Josh: Is it the declare the constant of a new function?

[00:11:53]
>> Will Sentance: You're spot on.
>> Josh: As the function createNewFunction.
>> Will Sentance: Yeah, exactly, we are not immediately gonna go and create a new function, even though it's got another function inside, we do not go inside. That's only gonna be reached if we call createNewFunction. How do I call createNewFunction, Shaun?

[00:12:09]
>> Shaun: Parenthesis.
>> Will Sentance: Parenthesis, excellent. I will never go inside otherwise. If I never call createNewFunction, that code inside of there will never be defined, stuff will never be saved. The overall description of the function body is save, you can think of it almost kind of like a string of things that would be done later on.

[00:12:27]
A string of instructions to be done later on. All right, good, we declare a new function. You've got to get this piece down, this is almost an interlude. This is us understanding what happens when I return a function for another function. In order, the hard piece to follow follows naturally, all right?

[00:12:45]
New function's declared. It's gonna be the return value of calling createNewFunction. Suli, if I took the parens off the createNewFunction, and had just const new function equals create new function, what would I be storing in new function?
>> Suli: CreateNewFunction.
>> Will Sentance: Spot on, the entire createNewFunction definition. I would have just new function as another label for createNewFunction.

[00:13:10]
Wouldn't be a copy, it would just be another label for that underlying function stored in memory. Very good, Suli,but we're not doing that. Instead, we're saying go run createNewFunction, see what comes back, and that's what's gonna be stored in new function.
>> Will Sentance: Let's do it, ah-ha, new function is the return value, the output of calling createfunction().

[00:13:34]
And remember it could be anything. Whatever comes out, it could be a number, an object, it could be a function in JavaScript. So everybody together, when we start executing a function we create a new.
>> multiple: Execution context.
>> Will Sentance: Rick, I'm watching, we create a new?
>> multiple: Execution context.

[00:13:56]
>> Will Sentance: That's too fast. If you're more measured. A new?
>> multiple: Execution context.
>> Will Sentance: Execution context. Yes, it doesn't sound like a cult unless you do it in a sing songy voice. That is a sign and actually, I shouldn't make these sort of jokes. Good, I hope you all feel,

[00:14:17]
>> Will Sentance: That you can leave at any time, no this is, okay. This is not funny, this is not funny. All right good, okay so createNewFunction is called, what's the first thing we do inside its memory Michelle.
>> Michelle: We create a new function called addto.
>> Will Sentance: Excellent, there it is.

[00:14:33]
I'm gonna do this function in a slightly different color. Add2,
>> Will Sentance: There it is. Well, where's my nice new green pen? Okay, add2 as its function. Okay, JavaScript is literally storing the whole functionality associated with the label, add2
>> Will Sentance: Do we call that label, or do we call that function, we're gonna evoke that function, RD?

[00:15:01]
>> RD: Give me the question one more time.
>> Will Sentance: Are we gonna evoke, are we gonna execute that to at this point?
>> RD: No.
>> Will Sentance: What are we doing instead, RD?
>> RD: We are going down to return, add2.
>> Will Sentance: Excellent, return the entire function definition whose current label is add2.

[00:15:19]
But we're not returning add2, we're returning the function that has the label add2. When JavaScript sees the word return add2 it goes, add2, let me go look in memory what I stored in that label. It's this function, perfect. So return out that entire function definition, the whole thing, that is literally the words function, friends, numb, curly braces.

[00:15:43]
Return numb plus 2. And it's returning all of that function out. And it's gonna store it where, Victor? And what global variable or global label is it gonna store it?
>> Victor: Under new function.
>> Will Sentance: Exactly. There it is under new function. It used to be called Named add 2, not anymore, but it is still that functionality in memory, we've just passed it out, not copied it out.

[00:16:10]
It's the underlying function, we just passed it out and given it a new global label, a new function. Perfect, by hitting the return statement, what happens in this execution context, Victor? When we hit the return statement of an execution context with a function.
>> Victor: It goes away, right?

[00:16:25]
>> Will Sentance: It goes away. In terms of our call stack, it gets popped off the call stack. But it's deleted, and all the stuff in it that's not returned out, is deleted. But the function got returned out, so it ain't deleted. Cuz we gave it a new label out here, so it's not deleted.

[00:16:38]
Remember, posh word for deleting stuff from memory is, or is it deleting stuff when we close out an execution context, is automatic garbage. Anything that wasn't going to be used out here is garbage, wasted memory collection. All right, good so we're back out now in the global execution context.

[00:16:56]
The last line was newFunction, is going to be the output of createFunction, which it is. There it is, the output was a new function called add2. Well it was called add2 in here, now it's just the definition of add2 in the new label. So if I wanna now run, call, invoke, Ben, that inner add2 function out here, what label do I use for it out here?

[00:17:15]
>> Ben: newFunction.
>> Will Sentance: newFunction, excellent, and how do I run, call, invoke newFunction?
>> Ben: Parentheses.
>> Will Sentance: Parens, and because if I look at the definition, now we visibly. Visibly, we as developers, we're gonna look back at the definition of add2. JavaScript is not doing that. It literally passed the definition out and stored it in newFunction.

[00:17:38]
So it's gonna look in newFunction for the definition of add2. And what does it see it needs to receive, Ben?
>> Ben: A num.
>> Will Sentance: Exactly, an argument. So let's put, I don't know, 3. And we're going to store the result of calling NewFunction in?
>> Ben: A result.
>> Will Sentance: In result, excellent.

[00:17:55]
So Paul, we're going to create at this point a new?
>> Will Sentance: Box, what are we going to create when we execute newFunction?
>> Paul: We're going to do local execution context.
>> Will Sentance: Excellent, there it is. Into it we go. And, Paul, what's the first thing in our memory, for the first pairing?

[00:18:14]
>> Paul: The parameter?
>> Will Sentance: Which is?
>> Paul: It's called NUM.
>> Will Sentance: Excellent.
>> Paul: And it's assigned to the integer 3.
>> Will Sentance: Yeah and be really clear. I know I said this already, but do not think that JavaScript, when it sees newFunction, is going, what's newFunction? I'd better go and check the line before.

[00:18:31]
It's create newFunction. The line before will never be returned to. The line before, create an execution context, inside of which it created add2, was returned out, stored in newFunction, and at no point do we ever, ever, ever, does newFunction ever care about createFunction again. It only cared about createFunction in the sense of I don't yet know what to store in me, so I'm undefined while I go and run createFunction, get an actual value, this function, and store that function here.

[00:19:01]
Never think that it's newFunction is a command to go and run createFunction. It isn't, it's whatever at that moment you got out a createFunction and that's over. So it's the add2 functionality. So when we call a newFunction like below, it is just interested in the add2 functionality. It never goes back into createFunction.

[00:19:20]
Seasoned engineers get muddled about that. Do not let yourself get muddled. If we don't get that clear, all the iterated stuff doesn't follow, okay? So yet we can now run newFunction. Visually, we visually is what I want to say. We have to look back in to see what add2's definition is.

[00:19:37]
I wish we didn't, I wish we could put it out and inspect what newFunction is and see that functionality. That's what we're looking at and you're right, it says num is a parameter and set to 3. Where we are then going to return out 3+2, return out the 5 into what global variable, Paul?

[00:19:56]
>> Paul: Result.
>> Will Sentance: Into result, excellent. There it is.
>> Will Sentance: So thumbs in a second, on. I create a function called createNewFunction. I then create a placeholder newFunction that was gonna be whatever came out the bottom of running createNewFunction. Well, what came out the bottom was an entire function definition add2 returned out.

[00:20:17]
I now use the new global label newFunction for that functionality add2, forming those add2 to run it, pass in 3, add2 to it, get out 5 and throw it in the global constant result. Everyone's thumbs, you lost me, I'm totally clear. I have a clarification. Your clarification might just be, why the hell do we do this?

[00:20:38]
>> multiple: [LAUGH]
>> Will Sentance: Everybody's thumbs out.
>> Will Sentance: Okay.

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