This course has been updated! We now recommend you take the JavaScript: From First Steps to Professional course.
Transcript from the "Scope Exercise Solution" Lesson
[00:00:00]
>> [MUSIC]
[00:00:04]
>> Bianca Gandolfo: So I'm just gonna quickly go through the answers for this. So it starts off with 11 failures and 1 passing. And let's see.
>> Bianca Gandolfo: So I'm gonna walk through it with you, so here's one assertion. It says a function's local scope variables are not available anywhere outside of that function.
[00:00:32] So here we have this function called first function. And we call first function here. So then we enter into that function body. We set localToFirstFn to the string inner and then we exit the function. All this is doing here is it's stopping it from, whenever you have an error it will stop running your code, it will just break everything.
[00:00:56] This will stop that from happening so it will run the subsequent lines of code. And this one says expect actual to equal what?
>> Bianca Gandolfo: So we're setting actual here.
>> Speaker 2: What was the first function?
>> Bianca Gandolfo: Which string?
>> Speaker 2: The one that-.
>> Speaker 3: Inner.
>> Bianca Gandolfo: To inner.
>> Speaker 2: Right there.
[00:01:33]
>> Bianca Gandolfo: Like this?
>> Speaker 2: Which string.
>> Bianca Gandolfo: So we can check it. So I just saved, so I just saved that. And we can check it by coming into our spec runner and refreshing it. And we see that that didn't pass. So there's some assumptions here that we-
>> Speaker 3: Why did you skip the test above?
[00:01:51]
>> Bianca Gandolfo: Did I skip the, whoops, sorry. I'm in the middle of the screen. So sorry, let me start from the second one. So this one's the first one, here's the second one. So the first one is input to a function are treated as local scope variables.
>> Speaker 2: Is that a true statement?
[00:02:13]
>> Bianca Gandolfo: Yeah, so you want to, it's a true statement and then the code, you're trying to prove it right. So it's testing for this rule. So we have this function and it takes a parameter called name and then here we're calling function to equal with inner and so the parameter is now holding the value inner.
[00:02:42] And so ACTUAL equals inner.
>> Bianca Gandolfo: So we type in inner and then we save it. The saving part's really important. And then we go to our test and we're gonna refresh this page, and we see that it passed.
>> Bianca Gandolfo: Cool?
>> Bianca Gandolfo: And so the point here is that parameters to a function, or I'm sorry, arguments, whatever your input is, is gonna be local to that scope.
[00:03:19] So a function has access to the variables contained within the same scope that the function was created in. So here we created this variable outer, we have this function here that we call, and we say actual equals name. What do we expect that to equal?
>> Speaker 4: Outer.
>> Bianca Gandolfo: Outer.
[00:03:43]
>> Speaker 4: The kid can reach into the parent, but the parent can't go into the blender.
>> Bianca Gandolfo: Yeah, exactly, no parents in the blenders. I don't want that. [LAUGH] And then we can refresh it, awesome. So that passed test as well, that test passed as well.
>> Bianca Gandolfo: All right, so now we're back to the other one.
[00:04:08] A function's local scope variables are not available anywhere outside that function. So here's a function, first function. We set that variable, that local variable to inner. We call it and then here we are. So this is kind of a hint that it's expecting it to throw an error when we call this function.
[00:04:35] What is this gonna be?
>> Speaker 3: Null.
>> Bianca Gandolfo: Why is it null and not undefined?
>> Speaker 5: Cuz it's not declared anywhere in the global scope or in the scope outside of the first method?
>> Bianca Gandolfo: That's a good guess.
>> Speaker 4: Is it because of the expect thing, so that the code doesn't break?
[00:04:58]
>> Bianca Gandolfo: Well, actually it has something to do with this beforeEach. So beforeEach of these eight functions it's gonna set ACTUAL to null.
>> Speaker 4: Right, but because that expect doesn't actually run the code to set it to undefined, it just keeps it at null?
>> Bianca Gandolfo: So yeah, every time, it will set it null.
[00:05:16] It will reset it to null every single time. So if we didn't have that function there, ACTUAL wouldn't keep holding the previous value of ACTUAL from the other exercises if you're not careful.
>> Speaker 4: No, I understand that, but to make this exercise correct, the one we're on now, the ACTUAL is expected to be null.
[00:05:38] But the only reason is that ACTUAL really hasn't changed, because the before function changed it to null.
>> Bianca Gandolfo: Yeah, exactly.
>> Speaker 4: We started as null, nothing's changed it.
>> Bianca Gandolfo: Totally.
>> Speaker 4: And the reason nothing's changed it, I think, I mean, I guess my question is, is because you have that expect statement.
[00:05:52] That's kind of like, if it's gonna be undefined or an error then just leave everything the way it was.
>> Bianca Gandolfo: Right, it's because, yeah, exactly. Because this localToFirstFn, since it doesn't exist in the scope it will throw an error.
>> Speaker 4: Right.
>> Bianca Gandolfo: And it would stop running the code.
[00:06:07] So this ACTUAL doesn't have access to this variable.
>> Speaker 4: Right.
>> Speaker 5: She didn't have that before, what was it called, before each test at the top it would be. Because was the result of the previous test piece.
>> Speaker 4: Okay.
>> Bianca Gandolfo: Yeah. So the next one is, if function's local scope variables are not available anywhere outside that function regardless of the context, it's called in.
[00:06:41] So we have our first function here, and we have this variable first. And there's a little hint here. It says, although false, it might seem reasonable to think that the secondFn mentions the local second function, should have access to the localToFirstFn variable since it's being called here from within the scope that the variable is declaring.
[00:07:08]
>> Bianca Gandolfo: This is a tricky one. So we have our second function here. Sorry, we call secondFn here. But since this hasn't run yet, we actually even haven't gotten there. So we declared secondFn, ACTUAL = localToFirstFn. And then we expect this to throw, so this is where we're thrown, calling our secondFn in here, I'm sorry.
[00:07:37] I actually think it's gonna call firstFn first here and where that goes, it goes into this inner block, declares this localToFirstFn. Then it calls second function and then second function is setting ACTUAL to local first function. And this is tricky because this is something called lexicoscope, if you wanna read into it later, is that this doesn't have access to the localToFirstFn.
[00:08:09] So what do we expect this to be?
>> Speaker 3: Null.
>> Bianca Gandolfo: Let's double check it.
>> Speaker 4: So blenders can't access sibling blenders. I mean, our function one, second from first, like siblings if you will.
>> Bianca Gandolfo: Yeah, you can call it siblings I guess, but the point here is that, yeah, so, yes, siblings can't access inside other functions either.
[00:08:40] Yeah. Even though it may seem like you could because you're calling it from within that function.
>> Bianca Gandolfo: Cool.
>> [INAUDIBLE].
>> Bianca Gandolfo: So if an inner and outer variable share the same name, and the name is referenced in the inner scope, the inner scope variable masks the variable from the outer scope with the same name.
[00:09:01] This is from the slide where I called precedence. This renders the outer scope variables inaccessible from anywhere within the inner function block. So what's this one? So we have a function, or sorry, we have this variable outer and then we have this function that has the same name.
[00:09:20] Reset to inner. We set ACTUAL to sameName. What are we gonna expect ACTUAL to be?
>> Bianca Gandolfo: Anyone? I hear whispers, but I can't understand them. What about Kim, did you get this far?
>> Kim: No, because I didn't know what rule meant. I don't do unit testing, so I don't know any of that stuff.
[00:09:47]
>> Bianca Gandolfo: No worries. Anyone else get this far?
>> Speaker 3: I'd say outer.
>> Bianca Gandolfo: Outer? What do you think?
>> Speaker 7: Inner.
>> Bianca Gandolfo: You think it's gonna be inner? You're right. It's gonna be inner. Why is it gonna be inner and not outer?
>> Speaker 7: Because it only gets as far as the.
[00:10:08]
>> Bianca Gandolfo: Because if we think about the way it's called, so we call this function, so first we set outer up here and then we say awesome, there's this FN function, we skip it, we call it, and then at this point, we enter into this, to the function body.
[00:10:27] Now we set sameName to inner, and at that point, we're setting ACTUAL to sameName, and at that point, it's inner and that's why, when it's evaluated down here, it's inner.
>> Speaker 2: I was looking at the bottom, the next exercise.
>> Bianca Gandolfo: Okay. Looking ahead. [LAUGH]
>> Bianca Gandolfo: Awesome.
>> Bianca Gandolfo: So, the next one is if an inner and outer variable share the same name and the name is referenced in the outer scope, the outer value binding will be used.
[00:11:05] So, here we're declaring sameName. Great function, we skip over it. We call the function, we enter into the function body, we assign sameName to inner, we exit here on line 85 and then we set ACTUAL to sameName and since ACTUAL is in a scope that is outside of this function, it only has access to the sameName within the same scope and so that means that actual is going to be?
[00:11:40] Hm?
>> Speaker 2: Outer.
>> Bianca Gandolfo: Outer, yes. Then we save it and then we can check it and make sure we're right. Awesome, starting to get more greens.
>> Bianca Gandolfo: So a new variable scope is created for every call to a function as exemplified with a counter. So we have our FN function, we say cool restore it, we skip it, and then we call it and then we have, we call it, we enter into the body.
[00:12:23] We say var innerCounter equals innerCounter or ten and so if innerCounter, so if this is undefined, it will be false and it will skip to the right side and it will be ten. Otherwise, inner counter will be inner counter plus one, do we have inner counter? Okay. I see.
[00:12:55] So if there's no inner counter already, then it's gonna be ten and at this point it's gonna be 11, and then we set ACTUAL to innerCounter. So we call it once and what is this gonna be?
>> Speaker 3: 11?
>> Speaker 2: 11.
>> Bianca Gandolfo: 11. And then we call it again.
[00:13:16]
>> Speaker 2: Call.
>> Speaker 3: 11?
>> Bianca Gandolfo: 11. So it's gonna be 11 because every time we call the function, it creates a new scope and so innerCounter is never gonna change, cuz it's always gonna start off as undefined.
>> Bianca Gandolfo: Great.
>> Bianca Gandolfo: So, a new variable scope is created for each call to a function as exemplified with uninitialized string variables.
[00:13:56] So here, we have our function again. We skip it, right, to the end, we call it, we go inside, and we say we initialize a local variable at undefined and it says if localVariable is undefined, enter into this block. So ACTUAL is now alpha and then we're gonna skip the else and then we're gonna set this localVariable to initialized.
[00:14:33]
>> Bianca Gandolfo: And now we're gonna call the function. The first time you call it,
>> Bianca Gandolfo: What is it going to print out?
>> [INAUDIBLE]
>> Speaker 4: Alpha.
>> Bianca Gandolfo: Alpha, exactly. And then if we call it again? So, we call it again.
>> Speaker 3: That's initialized.
>> Bianca Gandolfo: Well, let's think about how it runs.
[00:15:02] So we call the function, we go back up here. It's initialized again as undefined. It says if local variable is undefined, enter in this block. And it says ACTUAL alpha, it skips it and then it says local variables initialized. So, mm-hm?
>> Speaker 5: Sorry, I got tripped up on this one.
[00:15:22] I thought local variable is null instead of undefined. Could you maybe touch on why it's not null?
>> Bianca Gandolfo: Sure, sure, so the reason that local variable is undefined is because whenever you don't explicitly define a variable, it's undefined. You have to actually set something to null. So, JavaScript will make it undefined automatically.
[00:15:47] But, so in general, if you want to set something to empty, it's best practice to set it to null and not undefined so that you can kind of differentiate between that and you'll notice that we Set actual to null before each time. That's us manually setting it. But here, we're just initializing a variable and it's just going to be undefined.
[00:16:05] The same way if you have parameters that don't have an argument pass and you reference those parameters, they're going to be undefined. So what did we decide this one was?
>> Speaker 5: Alpha.
>> Bianca Gandolfo: Alpha.
>> Bianca Gandolfo: Cool. So, let's check it.
>> Bianca Gandolfo: Awesome. So an inner function can act both as local scope variables and variables in its containing scope, provided the variables have different names.
[00:16:55] So here we have our outer name, then we have FN again, we skip it, we call FN, we enter into that body. We set innerName to inner and then ACTUAL is innerName + outerName. So, what is ACTUAL?
>> Speaker 5: innerouter?
>> Bianca Gandolfo: Mm-hm. Is innerouter. And the reason that ACTUAL can be set like this is because it's a global variable.
[00:17:29] And we see that has no var, so that's something important to note as well. So we check it. Great, only two more.
>> Bianca Gandolfo: Let's see.
>> Bianca Gandolfo: Between calls to an inner function, that inner function retains access to a variable in outer scope. Modifying those variables has a lasting effect between calls to the inner function.
[00:18:02]
>> Bianca Gandolfo: So here is our outerCounter. And we have a function. We skip it, we call it. We enter into the body an outerCounter = outerCounter + 1. So outerCounter is 10. So that means outerCounter is now 11. And we're setting ACTUAL to outerCounter. So what is ACTUAL?
>> Speaker 2: 11?
[00:18:27]
>> Bianca Gandolfo: Yeah.
>> Bianca Gandolfo: And then we call it again, call function. We go inside the function body, outerCounter. What's outerCounter again?
>> Group: 11.
>> Bianca Gandolfo: 11 plus 1, is 12. So now outerCounter, I'm sorry, now ACTUAL is set to outerCounter, which is 12. So what should we expect ACTUAL to be at the second call?
[00:18:57] 12. The difference here is that our counter is outside of our function. And since our child function here, our nested function, has access to that outer counter, it's still, it can change it, but it still has reference to the value. Cool, let's save it.
>> Bianca Gandolfo: Great.
>> Bianca Gandolfo: And then our last one.
[00:19:28] The rule about retaining access to variables from the outer scope still applies even after the outer function call that created the outer scope has returned.
>> [INAUDIBLE]
>> Bianca Gandolfo: So we have our outer function. And remember we skip over it? We call, where does this end? I see. So we skip over it down here.
[00:19:58]
>> Bianca Gandolfo: And then we run the outer function,
>> Bianca Gandolfo: And call it. And we go inside of the function body, we set counterInOuterScope to 10. And then we have our incrementing function, which we skip. We call the incrementing function
>> Bianca Gandolfo: And we say counter in outer scope plus one, when we set that, and then we return here to our expect statement.
[00:20:29] We expect actual to equal what?
>> Speaker 5: 11.
>> Bianca Gandolfo: 11. And then we call our inner incrementing function again
>> Bianca Gandolfo: And then what happens?
>> Speaker 4: 12.
>> Bianca Gandolfo: 12.
>> Speaker 4: So up to now, it's like the previous exercise.
>> Bianca Gandolfo: Mm hm.
>> Bianca Gandolfo: It's similar, but the difference here is that we're explicitly inside of a function.
[00:21:06]
>> Bianca Gandolfo: And now what is, what is this one? I would, to be a function. Let's see. Here we go, so I skipped this line. So then we have window.retainedInnerFn = innerIncrementingFn. So remember we put things on the window object, it makes it global?
>> Bianca Gandolfo: And then we call it here again, retainedInnerFn().
[00:21:35] And so once we call it, we go back in here. And then we do + 1 again. And since we still retain value in the parent scope.
>> Bianca Gandolfo: What are the, it's 13.
>> Bianca Gandolfo: Cool, so any questions about that exercise? It's pretty in-depth.
>> Bianca Gandolfo: If you read through all these rules in here, these are basically all the rules for a scope.
[00:22:19] So if you go through those a few times you will have been mastered all of the different scenarios for scope. Any questions? I'd like just one question, so. Someone gives me one question that would be great.
>> Speaker 4: So if you click on them, you get the actual.
>> Bianca Gandolfo: Yeah, if you click on them, you can see the exercise.
[00:22:48]
>> Speaker 9: I have a question.
>> Bianca Gandolfo: Mm-hm.
>> Speaker 9: I have one error remaining, I don't know which one it is. How do we find which one it is?
>> Speaker 4: The red X.
>> Bianca Gandolfo: Yeah I can look at yours if you want. Yeah. Great.
>> Group: The red X [CROSSTALK]
>> Bianca Gandolfo: Yeah the style sheet, there was an error with the style sheet.