The full video and many others like it are all available as part of our Frontend Masters subscription.

Kyle Simpson

Kyle Simpson is an Open Web Evangelist from Austin, TX, who's passionate about all things JavaScript. He's an author, workshop trainer, tech speaker, and OSS contributor/leader.

Kyle Simpson

You Don't Know JS

Kyle walks the audience through another example of how the JavaScript compiler will declare and execute variables and functions. This example includes a nested function which creates a nested scope.

Get Unlimited Access Now

Kyle Simpson: Before we broke, we were talking, we kind of introduced this idea of the scope mechanism and how the scope gets registered in the compile phase. How we look up LHS references. This example's going to more firmly concrete some of those ideas and show us some of the differences there.

We are going to pick up our pace a little bit because we want to make sure we get to a bunch of great stuff today. But the questions have been great. I don't mean at all to discourage questions. Please keep asking questions both here in person and as well there on the video stream.

Okay, so now you should be familiar with that terminology of LHS and RHS, so I'm going to require you guys now to respond, you guys that are here in person. Tell me what is going to happen when we try to compile this program. What is the first step when we try to compile this program?

Speaker 2: It's scope do you know about foo.
Kyle Simpson: Which scope are we talking about?
Speaker 2: Global scope.
Kyle Simpson: Global scope. We're compiling, we're not executing yet. So, what is the compiling phase going to do with line one?
Speaker 2: I will now expect something to be assigned to foo.

Or I now know foo.
Kyle Simpson: Okay, that's one way of saying it. A slightly more formal way of saying it would be to say, hey global scope, I have a declaration for a variable called foo. Okay? So I'm going to declare a variable foo and the scope would respond back, got it.

I've got them registered in the scope now. You can move on. And we're going to ignore the right hand side, because theres no declarations there. Where's the next declaration that the compiler's going to worry about?
Speaker 2: Line 3.
Kyle Simpson: Line 3. The function bar. So we're going to say, hey global scope, I have a function called bar, and I want to register him in the global scope.

And not only the name, but also the function, in this case, it's a function declaration. So, line 3's going to register that function. Now, we recognize that it's a function so, we want to go ahead and recursively descent in and compile that function, bar. Now, we're inside of the scope of bar.

How are we going to compile the scope of bar?
Speaker 2: Hey scope of bar, I would like to declare a variable named foo.
Kyle Simpson: Exactly. I have a declaration for a variable called foo. That's from line four. Okay, great. Line four has been declared. Moving on. What's next?
Speaker 2: Function, or scope of bar I have a declaration for a function baz.

Kyle Simpson: Exactly. Here's the declaration baz, the scope of bar responds back, good, I've got them registered. Now, we recognize it's a function, we recursively descent in. How are we going to compile the function baz?
Speaker 3: I just see the declaration of foo on line six.
Kyle Simpson: See a named parameter for foo, which is an implicit declaration.

So it will say hey scope of baz, I have a declaration. He's a named parameter, but I have a declaration for an identifier called foo, okay. Any more compilation that's going to occur? Any more declarations anywhere? Does everybody feel confident that we've now compiled our program? At least for the purposes of scope discussion?

Okay? Now, it's a couple of microseconds later, let's go ahead and execute. What we know is that line one is not going to have a var anymore so let's execute line one as an operation. How is line one going to be executed by the engine? What's the conversation going to look like?

Speaker 4: I have a left-hand side identifier named.
Kyle Simpson: Which scope are we talking to, we gotta be.
Speaker 4: Global scope.
Kyle Simpson: Hey global scope I have a.
Speaker 4: Left hand.
Kyle Simpson: I have an LHS reference for a variable called?
Speaker 4: Foo.
Kyle Simpson: Ever heard of him? What's the global scope going to respond?

Yes I have, here you go and he's going to give us a reference back to that variable. So then we proceed to make our assignment to it cause we got an immediate value so we make that assignment to foo. Everybody feel comfortable with line one? Moving on. Lines 3 through 11 don't exist anymore cause they were compiled away so we're moving on to line 13.

That's going to be our next execution. How is line 13 going to execute?
Speaker 4: Global scope do you have a reference?
Kyle Simpson: What kind of a reference?
Speaker 4: A function reference.
Kyle Simpson: It's not quite what it's going to say. It's gotta be an LHS or an RHS.
Kyle Simpson: So it is going to be an RHS, but why?

And here's the key distinction. This is kind of a weird way to define it, but it's your best what you.
Kyle Simpson: Not exactly. Here's the way to explain it. The reason it's an RHS is because it's not an LHS, okay.
Kyle Simpson: I know that sounds silly, but there's not an assignment going on with line 13.

The bar reference is not being assigned to, it's being used. So because it's not an LHS, it's an RHS. So on line 13, we say, hey global scope, I have an RHS reference for a variable called bar. Now here's why it's important, because the RHS reference is going to behave differently depending upon declared and not declared.

We'll get to that in just a moment. But I have an RHS preference for variable called bar, what's the global scope going to respond to, what's he going to say?
Kyle Simpson: Yeah I do, here you go, here's a reference to that variable so I can go and retrieve that value.

Now I go and retrieve that value, and what is that value? Line three it was A. Function object, okay? So I get back a function object. Now I see this open close parenthesis on line 13. And good news, I don't have to sweat it because I got a function back and I'm going to attempt to execute the function.

So line 13 will attempt to execute the function that we just retrieved from the bar variable, everybody feel comfortable with that?
Speaker 2: Does the scope turn this into an apply and assign it with this? Is that happening behind the scenes?
Kyle Simpson: No, if you look at the way the spec is written there are different rules for the way a function is called when it's called like it's called on line 13 versus when it's called with a dot call or apply and when we get to this discussion this afternoon Well maybe this morning, but we'll for sure see that.

Speaker 2: Great.
Kyle Simpson: Very clearly, okay. Okay, so line 13 we've called the bar function. Let's execute the bar function. How are we going to execute, starting with line 4?
Speaker 3: Scope of bar.
Kyle Simpson: Hey scope of bar, I have an LHS reference. It is really uncomfortable that I force you to use all this terminology.

Isn't it? I have an LHS reference for a variable called?
Speaker 3: Foo. Foo, ever heard of him? What is the answer going to be?
Speaker 2: yes.
Kyle Simpson: Yep. I have heard of him. So he gives me a reference back to that. Is the reference that I get on line four a reference to the local variable foo or to the global one?

Speaker 2: Local.
Kyle Simpson: Local.
Speaker 2: Local.
Kyle Simpson: It's clearly the local, because it was declared local. So it's kind of a first come, first served. I look for it in my local scope first and I only go fish if I don't find it there. So if I find it there it's always going to be used.

In a sense this is called shadowing, because now that I have declared a variable inside of the function bar. Everywhere inside of this function that I reference something called foo, it's always at worst going to be this guy and not that guy. Because every time we do a scope lookup we're going to find it first, first come first serve, in this function bar.

Everybody with that? So that's called shadowing. There's no lexical way for us inside, beyond line four or anywhere inside of the function for that matter, but beyond line four there's no way for us to say foo and mean the global foo. At least lexically, we could say something like window.foo but that's a different mechanism altogether.

Okay. Okay. So we've executed like four. Let's execute, remember that lines six through nine are not there anymore, because they're been compiled away. So let's execute line ten.
Speaker 5: We have an RHS.
Kyle Simpson: Hey scope of.
Speaker 2: Bar.
Kyle Simpson: Bar, I have an.
Speaker 2: RHS
Kyle Simpson: RHS reference for a variable called.

Speaker 2: baz
Kyle Simpson: baz, ever heard of him, what's the answer going to be?
Speaker 2: No.
Speaker 3: Yes.
Kyle Simpson: I heard a no, do you understand? We see was declared here right. Okay, so the answer is yes, I've heard of him because he was declared just recently. Okay, great.

I need to get his value. What is his value? His value's a function, right? So we go ahead and get that function value, and then how do we execute it? We call this open close parentheses so we execute that. So let's do the job of the execution engine, let's execute baz.

How is baz going to execute? Again we're not passing in a value here, so we don't have to worry about the assignment part of the parameter. We're just going to execute baz. How does it execute?
Kyle Simpson: Starting with line 7.
Speaker 2: Hey scope of baz, I have a left-handed reference for a variable named foo.

Do you know of him?
Kyle Simpson: Exactly. Good job. Hey, scope of baz, I have an LHS reference for a variable called foo. Ever heard of him? What's the answer going to be?
Speaker 2: Yes.
Kyle Simpson: Yes, because he was declared as in the parameter. So I get a reference back to that local variable and I can assign to it.

When I assign bam here am I assigning it to this foo or to that foo?
Kyle Simpson: Am I assigning it to this foo or that foo? Always to my local foo, right? Always to my baz copy of foo, right? Because of that shadow. Okay? Now, let's execute line eight.

How's line eight going to work?
Speaker 3: The scope of baz. Evan, do you have an LHS of bam?
Kyle Simpson: Ever heard of him?
Speaker 3: Nope.
Kyle Simpson: What's the answer going to be? Nope. Go fish. So where are we going to go next?
Speaker 2: Bar.
Kyle Simpson: A scope of bar. I have an.

Speaker 3: LHS.
Kyle Simpson: LHS reference for a variable called bam. Ever heard of him?
Speaker 3: Nope.
Kyle Simpson: Go fish. Where we going to go next?
Speaker 2: Global.
Kyle Simpson: Hey global scope. I have an LHS reference for variable call.
Speaker 2: Bam.
Kyle Simpson: Bam. Ever heard of him? What's the answer going to be?

Speaker 2: Just made him.
Kyle Simpson: I just made him for you. I'm such a helpful guy.
Kyle Simpson: Many people wonder. This is a very controversial part of this auto global thing that is kind of a nightmare. It's the bane of our existence, but you wonder. Now, I know that everybody in this room and everybody that's online, I know that everybody writes perfect JavaScript now.

Shockingly back int he early days people wrote bad JavaScript. I don't know how it's possible because we all write good now but they wrote bad JavaScript back in the day. And one of the things that was a problem is that they forgot to make their declarations and they left off their vars and things like that.

So that's one possible explanation for how we arrive at such crappy behavior. The fact of the matter is it's been removed, as it's strict mode, because pretty much everyone agree's that's terrible behavior, just shouldn't be there. Okay so we, yeah.
Speaker 4: In the result I've created a declared bam in global scope, and it's undefined?

Kyle Simpson: No, it's the assignment value, so we've finished executing line eight which assigns A to which variable? The global variable.
Kyle Simpson: Exactly.
Speaker 5: I have a question.
Kyle Simpson: Yeah.
Speaker 5: The baz, should it not take a parameter of type foo?
Kyle Simpson: You're talking about line ten, right?
Speaker 5: Yep.

Kyle Simpson: You're saying should line ten have a parameter. Well it could, but it doesn't have to. JavaScript doesn't require you, it's variadic functions, so you can pass in values or not pass in values. You can pass in too few or too many or whatever. So just for simplification purposes, I chose not to worry about the assignment of parameter values.

But, yeah you could pass in the number 42 here, on line ten you can pass that inside those parenthesis. And it would get passed along as the initial value for foo. So on line six and a half, foo would have that value that you passed in.
Kyle Simpson: Okay, we finished executing line 13.

Now let's execute line 14. Now, this is just a short hand way. It's kind of like doing a console.log but I'm asking to evaluate the value of that variable at the current time. So what is the value of foo on line 14?
Speaker 3: Var.
Kyle Simpson: First of all, how do we execute line 14?

Speaker 3: A global scope.
Kyle Simpson: A global scope, like an RHS. Why is it an RHS?
Speaker 3: because there's no
Kyle Simpson: because it's not an LHS, okay. A RHS reference, for a variable called foo, ever heard of him global scope. And what does global scope say?
Speaker 3: Yep.
Kyle Simpson: Yes I've heard of him, he was registered before.

What is his current value when I ask for his current value? Is it bam?
Speaker 3: No.
Kyle Simpson: Is it baz? No, it's clearly it's bar. Everybody follow that? Okay. Line 15, how's line 15 going to execute?
Speaker 2: Global scope, I have an RHS bam.
Kyle Simpson: Hey globalbscope I have an RHS of bam ever heard of him What's the answer going to be?

Speaker 3: Yes.
Kyle Simpson: Yeah. I created him just recently. What is his current value?
Speaker 4: yay.
Kyle Simpson: Yeah, It's the yay value. Everybody with me, so far? Alright, now let's execute line 16. How does line 16 execute?
Speaker 3: Global Scope.
Kyle Simpson: Hey global scope, I have an?
Speaker 3: RHS.

Kyle Simpson: RHS reference for a variable called?
Speaker 3: baz.
Kyle Simpson: baz. Ever heard of him?
Speaker 4: Nope.
Kyle Simpson: Nope. Okay, here's where it gets different, because in the other cases where we ask the global scope for an LHS and it went unfulfilled, it was an undeclared declaration, in non-strict mode it automatically created one for us.

With an RHS reference that goes unfulfilled, it's not going to automatically create a baz function out of thin air, because how could it possibly do that? So what it's going to do instead is throw us what's called a reference error. So line 16 will result in a reference error because there is no identifier baz that's in any scope that's accessible to that current line of code.

baz was existing inside of this scope, but he did not get registered in the global scope, therefore we cannot call him. Does everybody follow?
Speaker 5: That's true for both strict and non-strict?
Kyle Simpson: That's true for both strict and non strict. So in non strict mode, reference errors result from unfulfilled or undeclared RHS references but automatic globals result from unfulfilled or undeclared LHS.

In strict mode they both result in a reference error.

Ready to take your code to the next level?

Intense courses with world-class teachers and unlimited access to our growing library of videos for the great price of $39 per month.

Get Unlimited Access Now