This course has been updated! We now recommend you take the Deep JavaScript Foundations, v3 course.
Transcript from the "Compiling Function Scope" Lesson
[00:00:00]
>> Kyle Simpson: Thanks very much global scope, we've got a red marble in the bucket and we've got foo sorted into the global scale. We continue compiling the code, we come to line 3 and we say, hey global scope, I've got an identifier called var, ever heard of him? What's the answer?
[00:00:16]
>> Speaker 2: No.
>> Kyle Simpson: Nope, never heard of them. But now that you mention it, I've got a bar. I sort that red marble into that red bucket. Same scope, we're still in the global scope. Now we have an identifier called foo, and we have an identifier called bar. By the way, this identifier happens to reference a formal function declaration.
[00:00:36] Since functions are kind important cuz they're their own scope, lets go ahead a recursively step into that function and that creates a new bucket, a blue bucket, and lets go talk about the marbles that go into the blue bucket. So now we're in the scope of bar, we're talking to a different scope manager.
[00:00:54] Now we're talking to the scope manager for the blue bucket. And we again continue looking for formal variable declarations. Hey, scope of bar. I'm on line 4. Hey scope of bar, I have a formal declaration for a variable called foo. Ever heard of him? The answer is.
>> Speaker 2: No.
[00:01:10]
>> Kyle Simpson: No, but now that you mention it, let's put that blue marble into the blue bucket. So now there's a foo in the blue bucket. That is important to note that that foo is different from the foo we found on line 1, cuz these are different scopes. And I'm probably not telling you anything by the way, that's surprising or groundbreaking.
[00:01:29] This is all intuitive stuff. It's just more formal and rigorous than you're used to thinking. I promise there's a payoff to that formality and rigor. It helps us avoid mistakes of thinking that lead to later bugs. Just more formal and rigorous. Okay, so now we have two different foos.
[00:01:46] And by the way, there's a term for having two different variables of the same name at different levels of the scope, like we see there. There's a term for that, and it's called shadowing. If, on line 4 and a half, or even let's say, on line 3 and a half.
[00:02:03] If on line three and a half, in between line 3 and 4, I said console.log foo, what do you think it would print?
>> Kyle Simpson: On line 3 and a half, if I said console.log foo, it's actually going to print undefined.
>> Kyle Simpson: Because this is a two pass system, we are handling the variable declarations long before we ever do the execution.
[00:02:36] So, at the time that we register a foo into the scope of bar, that's a compile time. We haven't paid any attention to the console.log yet. That's execution. Later when we go to execute, we're gonna come to line 3 and a half, and we're gonna be like, I'm looking for a blue marble.
[00:02:50] Guess which one we're gonna find. The one that's in our nearest scope. You see your problem, when you all just said it's gonna print out bar, your problem is you're thinking top down single pass.
>> Kyle Simpson: This happens all the time, people run into these problems. When you try to simplify JavaScript to something it doesn't do, big surprise you end up misinterpreting your code.
[00:03:13]
>> Kyle Simpson: So I am just trying to help you think a little bit more like the engine does.
>> Speaker 2: Now if the console.log was lined 4 to 5, then there would be "baz".
>> Kyle Simpson: Then it would be bars. [CROSSTALK] What's that?
>> Speaker 2: It will be undefined
>> Kyle Simpson: [INAUDIBLE] line 3 and a half.
[00:03:30]
>> Speaker 2: [CROSSTALK]
>> Kyle Simpson: What has been declared in that scope. It hasn't been given a value.
>> Kyle Simpson: Had it not been declared, Had line 4 not existed, then we clearly would have printed bar. We'll come back to that more of that execution stuff in a moment. I just want to point out, understanding how this processes from a compilation stuff is important to avoid misconception.
[00:04:00] So now we have a blue marble in that blue bucket, we have shadowed the one in the outer scope. And that means that nowhere within bar, no on line 3 and a half, not on line 4 and a half, nowhere inside of bar can we lexically reference the foo from line 1, it is impossible.
[00:04:19] Once we shadow at compile time, it's impossible at run time to lexically access something in an outer scope, there's no way to lexically say, I just want you to go one level of scope. There's a trick for accessing global variables which is not lexical at all, it is the global variables at the same, there are properties of the global object AKA window, that correspond to the global variables.
[00:04:44] So technically on line 3 and a half, you can say, window.foo and you'd get that quote bar value. But that's not a lexical thing, that's just cheating because global variables are also global object properties. If we were 18 levels deep in the nesting, and you wanted to access something from level 16 two levels up, that is not possible.
[00:05:08] If you do shadowing. So it doesn't mean shadowing is bad. Sometimes it's exactly what you want. Sometimes there's a descriptive variable name for different purposes, and different scopes, and it is entirely okay for you to shadow. Just know that if you do shadow, it means that you can not access the line above.
[00:05:30]
>> Kyle Simpson: So we've sorted that blue marble into the blue bucket for bar. Notice that we are done compiling the bar function. We finish and we recurse back out to the outer global scope. And we continue looking for formal declarations. Where's the next formal declaration that we find?
>> Speaker 2: We find it on line 7.
[00:05:51] We find a formal declaration for an identifier called baz. So we say, hey global scope I have an identifier called baz, ever heard of him? And the answer is?
>> Kyle Simpson: No.
>> Speaker 2: No. Cuz in that scope, we haven't seen a baz, so we add baz into the green bucket.
[00:06:04] I'm sorry, into the red bucket. We're still in the global scale. We put a baz, we put a red marble in there. Now the global scope has three identifiers, foo, bar and baz in it. And we notice that baz happens to point to a function, which gets its own scope, so let's step into that function and process that scope.
[00:06:23] Have I lost anybody yet? It should be fairly intuitive, so now we are in the scope of baz where we're talking to the green bucket, that's gonna hold the contents of baz. And we go looking for formal declarations. Where do we find the next formal declaration?
>> Kyle Simpson: The parameter?
[00:06:40]
>> Speaker 2: Line 7. It doesn't have a var keyword there. But parameters are in effect, formal variable declarations. They create, for all intents and purposes, local variables, not technically but for our purposes good enough. So foo is created as if it's a local variable inside of the scope of baz.
[00:07:03] It's like, hey scope of baz, I have this variable called foo, ever heard of him? And the answer is?
>> Kyle Simpson: No.
>> Speaker 2: No. Now that question's really important, because remember earlier I sent in strict mode, if we have a parameter, we have to check to make sure that we haven't seen that parameter before.
[00:07:19] Because if we have, that's an error. So, if we were in strict mode and we said hey scope of baz, I have a parameter called foo and baz is like well, I already got one called foo. Then what do we do? We got to throw an error, right?
[00:07:34] So that's why that Q and A that's going on is so important. division of responsibility. In this case, we don't have a foo yet in the scope of baz, so we make a foo, we put a marble into the green bucket. Now, we go through the rest of the contents of the baz function.
[00:07:50] [COUGH] Do we find any more formal decoration?
>> Speaker 2: Some of you may be wondering, what's going on with line 9? Some of you may wonder, is line 9 a declaration? Let's think about it from the perspective of what the JavaScript compiler can be doing at this moment. What does it know, and what does it not know?
[00:08:17] Line 9, when it finds a variable called, bam, it does not see the var key right there, we can all agree with that, right? So what does it possibly know? Could it assume that we meant to put a var there and we didn't? Well let's think about the other possibilities.
[00:08:35] It is entirely possible, that we might find a var bam on line 9 and a half, we don't know that yet cuz we're on line 9 still. It's also possible we might find a var bam on line 11, we haven't gotten there yet. It's also internally possible that we might find a var bam in an entirely different file, because each file gets to add to the global scope.
[00:09:02] They're all separate programs that share the global scope, so the next file load might make a var bam. So at this moment when we're processing line 9, can we say anything at all about bam other than it's not a formal declaration? Can we imply or assume where it is going to eventually be?
[00:09:24] And the answer is no. We don't know anything about line 9 other than its not a formal declaration, and therefore we cannot assume anything about it. So line 9 is no different than line 8 from the perspective of the scope manager and the compiler. We can all say, well wait a minute, I see the foo, but I don't see the bam.
[00:09:44] And we know the run time is gonna do different stuff. But that's all having perspective that the JavaScript compiler cannot have at that moment. At that moment, the only thing you can do is say, it's not a declaration, so I'm not going to worry about it. I'm not gonna sort that marble into a scope yet.
[00:10:02] We'll figure that out later.
>> Speaker 2: Having finished the baz function, we then continue and say, is there any more in this program for us to compile? Finding that we're at the end of this program, we're just gonna assume that maybe there's some other stuff there that we don't see.
[00:10:21] But finding that we're at the end of the program. We're now done withe the compilation stuff. Of course the code has been generated. It's ready for it to execute. But the important part is that all those scopes are sorted out. Everybody with me there? All those marbles. All those buckets.
[00:10:38] They're already sorted.