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

The "Inner Function" 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 explains how data is processed within the inner function, and shows that the return value can be assigned to a global variable.


Transcript from the "Inner Function" Lesson

>> Will Sentance: I now want to switch to something totally different before we bring this together, which is calling a function, just as we have done 1000 times. Inside of another function and then asking ourselves, if I don't find the data that my inner function needs inside my inner function execution context, where do I get to go and look next?

Probably we'll get that just one step out or is it? Line one, let's jump straight into this, this is not complex code. Line one here, Sam, what are we doing in global memory?
>> Sam: Declaring a function
>> Will Sentance: Declare the function, specifically.
>> Sam: Outer.
>> Will Sentance: Outer and there it is stored into global memory.

There it is, leaving white. Okay, excellent, Virginia, next line all the way down we go to and run
>> Virginia: We're executing outer.
>> Will Sentance: We're executing outer. Okay, there it is. New, brand new.
>> Group: [CROSSTALK]
>> Will Sentance: Thank you to only one of our community here, let's try it again.

A brand new
>> Group: Execution context.
>> Will Sentance: Thanks to everybody, but especially to Bhuvanesh. All right, so, there's our execution context, let's add it to our call stack. There it is. Outer on the top of the call stack. I hope we leave in the recorded version of this. Our wiping down of the white we can do full for special features.

There. Ours is executing into it, we go in the local memory. Bhuvanesh, the first thing in the local memory is.
>> Bhuvanesh: Counter
>> Will Sentance: Counter set two.
>> Bhuvanesh: Zero.
>> Will Sentance: Zero, excellent. Then we declare a function Michael, what is it?
>> Michael: Increment counter
>> Will Sentance: Increment counter. There it is.

And now we're going to use increment counter and execute it with parentheses on the end of it to say go run it inside of outer. Let's add it to the top of call stack increment,
>> Will Sentance: Counter, brand new.
>> Will Sentance: [LAUGH] Bhuvanesh, you're a hero. What is wrong with the rest of you?

Everyone together. Others go ahead with their hand now at this point. Thank you David as well, I told David excellent. Alice just has her head in her hand at this point. Everyone together, a brand new-
>> Group: Execution context.
>> Will Sentance: The joke that never gets old, there we go into it we go and nothing in local memory time, well I guess I'll put it there.

Nothing in local memory. The first line I hit, Michael, says to be what?
>> Michael: Add one to the counter.
>> Will Sentance: Yeah, I like that, counter ++. I'm using this green for my looking up. Jasmine, increment counters top of my cool stack. I'm running inside it right now. I don't find, well where do I start?

Where do I look for counter first?
>> Jasmine: In your local execution context.
>> Will Sentance: In my local execution context, excellent, into it let go. Do I find, Jasmine, counter in the local memory?
>> Jasmine: No.
>> Will Sentance: No, I don't. Where do I go next?
>> Jasmine: To the next outer-
>> Will Sentance: Exactly, I go out.

>> Will Sentance: And find counter is?
>> Jasmine: Zero.
>> Will Sentance: And I do what to it?
>> Jasmine: Replace it with one.
>> Will Sentance: Yeah, exactly. I heard that replace it with one by the way, that's nice, exactly, yeah, exactly. In other words, it looks to me like I go down my call stack to outer.

>> Will Sentance: And that's what everybody thinks. And yet right now, I couldn't tell you whether it's because I'm calling increment counter inside the calling of outer, whether it's cuz I'm calling increment counter inside my running of outer only got inside about because I'm running outer. So that's why I'm inside of it, inside of which I call increment counter.

I can't tell you whether it's a fact that I'm calling it inside an increment counter. And you may not even have made this step, but where many of you I'm sure have or whether it's the fact that I saved increment counter inside of outer. Because right now it could be either.

Is that I saved increment counter inside of outer or that I invoked increment counter inside of outer. That means when I don't find counter inside the local execution context memory, I can take a step into outer execution context memory. Because it's not automatic. We might look at that and go, of course it can step out of the box inside a bigger box but that's not built into a language.

That is not an automatic feature, that is a decision by language to say if I don't find data in my immediate local memory, I can go look in another local memory for it that's not automatic. And right now I couldn't tell you whether it's about I saved increment counter there or ran it.

>> Will Sentance: There is a way I could figure it out, though. If I could run increment counter out here in global, I could then assess, do I have access to the data from where function was born saved originally in other words it's where I save my function that determines what data I've access to.

Or do I only have access if I'm running increment counter out in global. I guess only have access to increment counter's memory and global in which I'm running it. But then how do I get increment counter out of outer? I'm allowed to do that, Jasmine? No, I’m gonna get some sort of error.

Eric, how can I get increment count out here so that I can run it?
>> Eric: You can return it from the function and assign it a new variable.
>> Will Sentance: Exactly, return it from the function call, assign it to a new global label. Let’s do exactly that. What happens here In an error can't run the function outside of where it's defined.

There is a way to run a function outside where it's defined without an error. We return the inner function of assigned to a new global label and use it out here. And now we can pull the funds that was originally saved as increment counter by its new global label, new function.

Let's go. Let's see what happens people. So, I heard some really interesting things that people were talking through there. We're gonna save that outer function, we're gonna call it, we're going to return out that little baby increment counter function from inside out into a new global label new function.

And we're gonna call it by its new global label and some really interesting stuff is gonna happen. Stuff that's gonna give out function superpowers, in a special way. So here we go, line one, Andrew you are up. What are we doing in line one?
>> Andrew: Declaring a function.

>> Will Sentance: Declaring a function folk technical communication means total precision and completeness. Andrew take it away, declaring?
>> Andrew: A function to outer.
>> Will Sentance: Exactly to carry a function named outer. There it is. Thank you to Andrew for his patience with me. Sam next line. Left hand side first.
>> Sam: Declaring a new label.

>> Will Sentance: Yes, well done. New label, new function exactly. We do not know yet what to store in it because we've got to go ahead and run what Sam?
>> Sam: We need to run outer as a new.
>> Will Sentance: Perfect, we need to run outer folk, let's have our call stack going here.

There it is, global on the bottom, we add outer. Next,
>> Will Sentance: Bhuvanesh, we're executing outer, we create a new?
>> Bhuvanesh: Execution complex.
>> Will Sentance: Execution complex, thank you Bhuvanesh we appreciate it. That's a very on point, into it we go. And,
>> Will Sentance: We immediately, no inputs, no arguments. So instead, in local memory, Jasmine, we immediately assign what?

>> Jasmine: Counter to zero.
>> Will Sentance: Counter to zero, excellent. Michael, next line. I do this thing where I give the same person the same question, every single time without thinking about it. Michael, next line.
>> Michael: We create a function called the increment counter.
>> Will Sentance: Increment counter, Jasmine, did I ask you for 0 last time?

Yeah, I did, and I asked you for increment counter, that's so interesting, what is going on in my mind subconsciously that does that? That process probably whatever that means, all right? Increment counter is saved, we're not gonna use it inside though, instead, we are going to take its code, or if you remember from our heap piece, we take the label to it's under the hood stored function.

Wait, sorry, address if it's under the hood, stored function and title, but we'll just for our purposes, take the code of increment counter. We're gonna see what? Well, what are we gonna do, Jasmine? We're not gonna return, we're not gonna run increment counter, we're going to?
>> Jasmine: Return it.

>> Will Sentance: Return increment counter, so it's gonna say return increment.
>> Will Sentance: Counter, we use that to look up increment counter, it's the code of increment counter without a label. And we take it, Jasmine, and we return it out into?
>> Jasmine: newFunction.
>> Will Sentance: Into newFunction, she's spot on. And it used to be called increment counter, it's not called that anymore.

I'm just putting it here, so we know it used to be called that. And there it is. And its only code is counter plus plus. And our execution context here, everybody, is what?
>> Group: Gone.
>> Will Sentance: Pop it off the call stack, exactly, removed. We pop it off,
>> Will Sentance: We pop it off the call stack.

>> Will Sentance: There it is, gone. And we're out to global, where newFunction is now our new global label for the function that was born inside of outer as increment counter. Let's run it people, and let's see what happens, newFunction is called brand, everyone together, brand new, [CROSSTALK]. Thank you, that energized me after my silly lack of enthusiasm, there it is, it goes on the call stack.

The newFunction is added on the call stack. We go into it, nothing in local memory assigned, instead we hit immediately what line, Jasmine?
>> Jasmine: The counter plus plus.
>> Will Sentance: Counter plus plus because the newFunction is the functionality formerly known as increment counter. Where, Jasmine, do I look for the counter first?

>> Jasmine: [INAUDIBLE]
>> Will Sentance: Yes, excellent, thank you, in the local execution context. Again, same question, to you again. Anything there?
>> Jasmine: No.
>> Will Sentance: No, now, where would everything, every intuition we've thought over the years suggest, given we first check top of our call stack and newFunction, where we would look next, Jasmine?

In every sort of intuition we have about, I run my function here, I have access to stuff outside of where it's running, where would I say I can go and look for counter next?
>> Jasmine: Maybe we think to look in outer.
>> Will Sentance: We might think looking outer, but outer's off the execute, that execution context is shutdown.

It's off our call stack, therefore, we can't take our thread back in there, that's done. Our thread of execution went in, came back out, and it's gone. We're now inside of newFunction. So we're running newFunction in global, so Jasmine, where might we look for counter?
>> Jasmine: Global.
>> Will Sentance: In global, in theory, sounds right to me.

>> Will Sentance: [LAUGH] This line is not very good. Is counter in global, Jasmine?
>> Jasmine: No.
>> Will Sentance: It's definitely not.
>> Will Sentance: This never gets old. [LAUGH] No, very sad.
>> Will Sentance: Very sad. What was it by the way, what a problematic language design that lets this happen? Like this feels like a bad language design, honestly.

Given this is not the core focus of this tool, we wanna use this for a very powerful feature, I'm not gonna dwell on this, but I'm not gonna sort of let us suffer for too long. Instead, I'm gonna tell you about a powerful thing that happens when I return a function out of the running of another function, give it a global label and run it by its new global label.

Something very special happens. I do not just get the code of the increment counter function returned out into newFunction. I bring with my function code something else. On the back of this function, comes,
>> Will Sentance: On the back of this function, comes,
>> Will Sentance: Its entire surrounding local memory. As the function gets returned out, gets returned out into newFunction, it brings with it, attached on to it, on the back of the function.

And here it is on the back of the function in a little backpack as the function gets pulled out, it pulls with it on his back the surrounding data, from when it was born. And look at that, there is counter 0 attached too, and we'll talk about how, and we'll talk about whether there's any more official name than backpack.

[LAUGH] I will tell you this I read a blog post about it, it has 50,000 likes, meaning this term is ever more popular. May enter the spec of JavaScript, never but maybe. There it is attached on the function meaning, Jasmine, take a shot after not finding counter in newFunction's immediate local execution context.

You rightly said the local memory there. Before I look to global, might there be somewhere else? And you can use the word, you can say the word, it begins with b, and it ends in ackpack. Jasmine, is there somewhere else you think that JavaScript is gonna take its look up journey to before it searches global for counter?

>> Jasmine: You might look in newFunction's backpack.
>> Will Sentance: You will look in newFunction's backpack. Thank you so much, Jasmine, she is spot on. Off we go into newFunction's backpack, here it is. And what do we find there, Jasmine? We find counter is?
>> Jasmine: 0.
>> Will Sentance: Counter is 0, she's spot on.

What do we do to it? We increment, Jasmine, to?
>> Jasmine: 1.
>> Will Sentance: To 1, this execution context, gone. I'm not gonna erase it, we're gonna add it back home because we're gonna run newFunction again. We're gonna talk about this backpack in a moment, people, it's super powerful.
>> Will Sentance: Everything in the local memory, there's nothing here, but everything as always is deleted, it's only temporary.

Run newFunction again, brand new, Anna, brand new, what?
>> Group: [CROSSTALK]
>> Will Sentance: Excellent, everybody, but Anna as well, excellent, Anna. Into it we go, when they turn up the audio for your mics and it's just Bhuvanesh saying, execution context. [LAUGH] What we find in As next code to new function counter, plus plus.

>> Will Sentance: Eric, where do I look for counter first? By the way, just to be clear, there's a new function execution calls on the call stack. I erased it and put it back on again. And where do I look first, Eric?
>> Eric: Sure going to look in the local execution context.

>> Will Sentance: Fantastic, do I find counter?
>> Eric: No counter there?
>> Will Sentance: Where do I look next? Don't use any fancy terms.
>> Eric: We're gonna go to the backpack.
>> Will Sentance: We're gonna go to the backpack where we find counter is.
>> Eric: One.
>> Will Sentance: Ha, wow. We find counter is 1, we increment it to 2.

>> Will Sentance: Immediately people, you might be able to see, this has supercharged our functions. Functions are just two things. Well, that's for now say, two blocks of code which when run, they get to walk through the code, the thread, and a temporary memory bundled up just for the function at that time.

This enables our functions to have two types of place to store data. One temporary for their single execution, their single running. And one permanent, persistent, that's there as long as the code of the function is saved. Our function's not just code anymore. It saved code under the label new function that was originally increment counters code, plus persistent data attached to it.

That we get access to by making reference in new function borders increment counter to something that's not in local memory. So we jump out and look in the backpack. And as long as when we birthed, when we created the now known as new function function originating from encounter.

We had around it in local memory save counter is zero. That gets pulled out on the back of the function into new function. And there, it is attached. There, it is attached, people. Folk, I'm going to, [SOUND] I will stress this one more time, new functions definition, its code, its saved code now has a hidden link hidden.

Well, that's why I gotta start to tell you a few more important things about this before we move on to. How is this hidden? How is this permanent data here attached to the function? Well, firstly, we can't get to it directly. I can't go new function in global, newFunction.backpack.counter, this is not possible.

I can't even go newFunction.officialNameForIt.counter. There's no way of getting into it. It is absolutely, they call it, private to that increment counter, now known as new function function call. We can only get into it by running new function. Not finding something we reference in the local memory and jumping out to the backpack.

The backpack kind of inserts itself before we go it down to looking in global. Don't get me wrong, the backpack in global in the sense that it's attached to a function that is saved in global. But global reading means I can access the name for that data when I'm in global execution context.

I can't access this data, it's hidden, it's protected. Well, how is it protected? Well, as soon as a function increment counter was saved inside the running of outer, when outer was on our call stack earlier, when outer was on a call stack, I got over it inside its execution context, the thread was running through.

As soon as increment count was saved, it immediately got a link to the surrounding memory. Immediately because the whole surrounding memory, that link was stored on a property square brackets, square brackets, two square brackets, scope, square brackets linked to this running memory. Old copy, just a link to where it was literally stored.

When I returned the function out, I pulled out, on that link, all the data with me attached to the function. So we got that scope, property. There it is. Half the lead, half of the lead is returned. John, amazing. There it is. I was about to start shaking again, I thought.

Okay, meaning, I'd say whenever new function runs and it doesn't find counters local memory, it goes through its definition, looks into its hidden scope property, in other words, into the backpack, and finds counter. Because counter was there when it was born and when it got returned out, the code of increment counter from running outer.

We ran outer, we returned increment counter from creating it inside outer and we returned it out into new function. When we run new function and it doesn't find counter in the local memory and looks to new functions backpack stored on the scope property. I wanna do films so I want to probably tell you a few more pieces about this backpack first.

Firstly, it's really optimized. JavaScript makes the link on the saving of increment counter inside of outer, to the surrounding local memory, everything in there. The link to the whole collection, everything. There's a link to where this is all sort in memory. But on returning out that function, normally when you finish running a function, what's the only thing we hold on to, Sam?

When I finish running a function, return out free, all the other stuff in the local memory, do we hold on to it? No, we automatically garbage collect it. Why is it called garbage? It's called garbage because we can't access any of that data by his name anymore. So there's no point it being there.

We automatically collect it, it means it automatically gets deleted by JavaScript.
>> Speaker 10: It's a weak reference.
>> Will Sentance: Sure, this is, absolutely. Instead here, we rely on, when we return out this function, JavaScript is gonna hold on to all that surrounding data in the backpack of the function. But hold on, what if I save maybe ten different things in this local memory?

I return our increment counter into new function, run new function. I've got ten things in this local memory besides counter. What's the only thing, Alex, inside of new function for me, was increment counter, was the only thing I refer to, Alex?
>> Alex: Counter.
>> Will Sentance: Counter. So if I got ten other things in this backpack, can I get access to any of those?

No, I can't access anything that's bad. I can't go like new function.scope.counter, I would want to. I want this to be preserved and protected for the running of the function. Meaning, JavaScript knows on the returning of increment counter out of new function, it already knows what that function could ever end up needing or accessing.

And so it optimizes what gets pulled out in the backpack once we exit outer and delete everything else in the local memory. If it's not referred to delete it.

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