JavaScript: The Hard Parts, v3

Calling Function within Function

Will Sentance
Codesmith
JavaScript: The Hard Parts, v3

Lesson Description

The "Calling Function within Function" 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 shares a code example where a function is called from within another function. This demonstrates the inner function is able to reference any memory from within the outer function, including a counter variable.

Preview

Transcript from the "Calling Function within Function" Lesson

[00:00:00]
>> Will Sentance: Calling a function in the same execution context as it was defined. We're going to define a function outer, call it. Inside of outer, we're going to define counter as zero. We're then going to define a function, add1, and we're going to invoke that function. Not too hard. Very familiar, very relieving, this sort of code. This is very good to follow. This is going to though raise a question that until we can answer, we can't understand closure.

[00:00:36]
But if we can answer it, it will enable us to understand closure. Let's walk through this code. We're going to define a function outer in global memory. Actually, I've not called much on Matt. Matt, if you don't mind, talk me through. We're in, this is code that's not going to be too troubling perhaps for us, but let's go through it nevertheless, because it's going to raise an important question for us that if we can find the answer to, we have all we need to understand this most profound, elegant concept, that of closure.

[00:01:11]
But let's start with this. Matt, what are we doing in line one? So in the execution context, we will declare a function called outer. Yes, in the global, exactly, in the global execution context, yeah, absolutely. Declare outer. There it is, it's code. Do we do any of the code inside of it yet, Matt? No. No, instead we jump down to what? We jump down to outer, which we did, what am I doing? Oh no, sorry.

[00:01:40]
Ah yeah, exactly. Outer and we're going to do what with it? We are going to execute it due to those parentheses. Yes, beautiful, and into it we go where we are going to have, we create a new execution context. Yes, exactly. The thread is going to weave in. We have our local memory, it's just the smaller version and the bigger version, the bigger thing. And what's the first thing we save in there, Matt?

[00:02:10]
So to the variable, a let variable, we create counter and assign a value of zero. Beautiful, and then we declare what? And then we declare a function called add1. And if ever you've seen this before, people, I've always used increment counter, but because I just hate writing increment counter for so long, I've had one, but it's going to do, well, we don't need to know yet, do we, because we don't go inside it, we just save its code.

[00:02:35]
But do we run it? It looks like we do. How do I know, Matt? The parentheses. Beautiful, and so, let me just do my call stack because we are doing something even a little bit more complex here now, right? Functions. So we've got the global execution context, as we heard from Matt. We have added outer because we've gone inside it, but now, Matt, we're calling what inside of outer. Then we call add1.

[00:03:09]
Beautiful. Add1. What do we then create? We create a brand new execution context. We add it to our call stack on top. So we now know that the thread of execution has woven into running add1. It's on the top. When we finish running add1, where will we go back out to, Matt? After we finish doing add1, will we, the counter in, well, just so we know in terms of our execution context and our call stack, we went into outer, we added to the call stack, we then started running add1 inside of it, we added it on top, so we know the execution context at play is the top thing, it's add1.

[00:03:46]
When we finish running add1, just get ahead of ourselves for a second here. Where will we go back out to? Would we go back out to outer? How would we know? The what's below, exactly. We'd pop off add1, straight back out to outer, great. So that's where we would go, but before we do that, we've got something to do inside of add1. Its local memory must be also set up, and what line of code do we hit inside of add1, Matt?

[00:04:13]
So then we've got counter. Then we add one to it. Yeah, counter plus plus just means find counter, add one to it. Where do we look first, Matt? We check first and, and since it doesn't exist. We check first in add1, do we find counter, Matt? No, we do not. Do we panic? No, no. Where does JavaScript look next? And it will take the call stack, jump to the next. Ah, that feels very fair, it goes out to and finds counter and does what to it?

[00:04:48]
It adds one. Beautiful. Word onto Matt. OK, beautiful, and then we finish running add1, its execution context gets closed, we pop it off the call stack, pop it off the call stack, we go back down to outer. Is there any more code to run in outer, Matt? No. Nope, so we jump out and we go down back out to where, Matt? Global. Global. Spot on, let's give Matt a hand because that's good stuff. Thank you, Matt.

[00:05:18]
Problem, Matt actually said something that is, I can't tell is true or not yet. Matt said, when we couldn't find counter in the local memory of add1, we went out to outer's memory, its execution context, found counter is 0 there, and added 1 to it because we went down the call stack, because add1 was being called, run inside of what function, Matt, you just said it. We're running add1 inside of what function?

[00:05:54]
Outer, outer. That's why we could go out to find counter there, surely. Except it's ambiguous. We also defined, saved, declared, stored, add1, inside of outer. We ran it inside of outer, but we also stored it there. It could be for either reason that we stored it in outer, or that we ran it, add1, in outer, that meant that when we didn't find counter inside add1, we went out to outer. Right now I couldn't know, because I called it in exactly the same place as I saved it, as I defined it.

[00:06:31]
Matt assumed, well, it must be because of the call stack, I can go down and look at outer. But it could actually be because I saved add1 in outer, that means when I run it, I have access to, that's where I check next. Right now I don't know. But the answer to that question will be the essence of closure, the title of the talk, the essence of closure. I mean, it does have a clue there, but on the bottom here it says where you define your functions determines what data it has access to when you call it.

[00:07:07]
But for now we don't know, we can't tell. But if we can work out the answer, then we have everything we need to know to implement this most elegant, powerful feature of JavaScript, closure. How could I test my hypothesis, that sounds so fancy, right? How could I test this open question, is it where I define the function or where I call it, that determines, is it where I save the function, or is it the fact that I saved it here that when I run it, and it doesn't have counter in local, it goes to outer, or is it because I ran it?

[00:07:38]
Add1 in outer, is it because I saved add1 in outer, or is it because I ran add1 that means when I run add1, it has, after not finding counter in local, it goes out to outer. I'm totally with Matt, Matt's like, well, it's been run there, it's down the call stack, that makes sense. But it could easily be because I defined it there. We don't know yet. How could I test? How could I run the add1 function somewhere else, yeah, Joe, other than where it was defined?

[00:08:11]
We could, for example, have a return at the end of function outer that returns the add1 function. Yay. I'm sorry there's too many rounds of applause, but that's just so good from Joe, thank you, Joe. Last round of applause, no more in the entire session, very good. We could do that. Calling a function outside of the function call in which it was defined, calling the function outside of where we saved it, we could do that by rather than calling add1 inside of outer, instead we can just return out our add1 function into global and run it out here.

[00:08:59]
What data or what journey of lookup that we take will be determinative of whether it's where we define our function or where we run our function, that determines what data we have access to. But I will be really clear, when we return our add1, that outer execution context is going to close. So we've got an interesting puzzle ahead of us.

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