Scope in JavaScript - HTTP 203

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
SURMA: Oh, look. He's adjusting it. SPEAKER 1: It looks straight. It does from here. JAKE: I mean, it doesn't look it. SURMA: It really does not look straight. SPEAKER 1: There it is. SPEAKER 2: Yeah. SPEAKER 1: Camera 1. SURMA: Then again, apparently, neither do we. BOTH: Hey. [LAUGHTER] [MUSIC PLAYING] JAKE: So. SURMA: So. JAKE: We had a chat in the office a couple of weeks ago. I mean, OK, we have today, as well. But I'm talking about a specific chat we had. SURMA: OK. JAKE: Specifically where we were looking at code like this. SURMA: Right. JAKE: So we've got your old scripty tag. SURMA: Scripty tag. Always good. JAKE: Scripty tag. Couple of variables in there. SURMA: A var, a const. All right, cool. JAKE: And again-- but this time-- SURMA: It's a module. JAKE: It's a module. And then the question we were posing each other is, like, well, what can be accessed? SURMA: What is available in the third script tag, which in this case is a module tag? JAKE: Well, OK. Now, the only reason it's the module tag-- right, OK, you're now making me go on a tangent already. The only reason it's a module tag-- SURMA: You're welcome. JAKE: --is because if it was a normal script tag, these would not run in this order. SURMA: Oh, because-- JAKE: Modules are deferred. SURMA: Implicitly. JAKE: Yes. SURMA: So if it was a script tag with defer, what is-- JAKE: It's ignored. SURMA: Oh, because it's inline. JAKE: Yeah. SURMA: Defer is ignored on inline script tag. JAKE: Yes, it is. SURMA: Today you learned. JAKE: There we go. So-- SURMA: Good tangent. Continue. JAKE: Now that we've got out of the way, yes, the only reason I put type module on this is-- SURMA: So we have a good order. They actually execute in order they appear on the snippet, right? JAKE: Exactly. SURMA: Good. JAKE: So you actually did a Twitter poll. SURMA: I did do a Twitter poll. JAKE: Not quite-- SURMA: It did not look like this exactly, but related. JAKE: Very similar. It had of some of the same things. And we thought of-- do an episode. SURMA: Yeah. Like I wanted to write a-- JAKE: Let's do an episode. SURMA: I wanted to tweet this. So I did a poll 24 hours, went to tweet the solution, then-- JAKE: And I said no. SURMA: No, you don't. JAKE: That's precious content. Hold onto that content. And I'll take credit-- SURMA: Otherwise we have to come up with [BLEEP] again. So this time we actually have, like, semi-good content. JAKE: Exactly. Exactly. Well-- well, let's-- let's not say that. SURMA: Let the audience decide. JAKE: Yes, let's let the comments decide if this is actually any good. SURMA: Oh, don't let the comments decide, mate. JAKE: Oh, OK. So I figured, like, let's start by talking about how scoping works in JavaScript. SURMA: Yeah, I mean what's that-- JAKE: That's really what this is all about. SURMA: Exactly. OK. JAKE: But we'll go back to the start. So back in olden times, ye olde "JavaScript-e"-- SURMA: This is like ES3 level. JAKE: ES3 time. The only way you could create a variable was with var. SURMA: Yes. Which is good, because that's what the "var" stands for-- a "variable." JAKE: It is. But you could also create functions. Yeah, that was in ES3 as well. SURMA: Shocking. JAKE: Yeah, we had those. But they behaved in very, very similar ways. So a var or a function would be scoped to the parent function or the global if there wasn't one. SURMA: Right. JAKE: So here we go. One-- SURMA: And I think it was two boundaries there that existed at the time. Like, you had a function or you had the global. JAKE: Hold onto that. SURMA: Oh, boy. Oh, boy. JAKE: OK. OK. So we've got, yes, a var one that is on the global; two on the global; three-- it's in a function-- so its scope to the function. And four is also scoped within two. So, like, you know. You couldn't call four out of here. That wouldn't work. SURMA: Yeah. JAKE: So if you did something like this, if you did var five inside an if and a function six, they would actually now exist in-- SURMA: Within two. JAKE: Within two. So you'd be able log them and everything would work. SURMA: Because blocks were just not a scoping mechanism. JAKE: So you could naively say that the only thing that has a scope in JavaScript in this era was a function or the global. SURMA: Mm-hmm. That's what I would have said. JAKE: That is what you would have said. There are two cases where that was not true, and still isn't true. SURMA: Hm. OK. JAKE: [INAUDIBLE] so. And so I will give you a clue that these are not places that you can create variables as such. But there are places where an identifier has a scope which is smaller than a function. SURMA: Oh, that's oddly-- the phrasing was so oddly specific. JAKE: Well, I'm trying to help. SURMA: Um. JAKE: And I love, like, putting you on the spot. I do this a lot in the videos. And it's stuff that I wouldn't get either, this is. SURMA: Technically, what about for loops? Go back. If I had the four var i=0, is that i available after the for loop? JAKE: Yes, it is. So that would go up into the parent scope. And we've done a video about let. SURMA: Well, that was let and const. JAKE: Right. SURMA: And so I wasn't sure if that was also some weirdness that-- JAKE: No. SURMA: And I didn't-- hm. JAKE: I thought this was going to be a short video, but I think now we should just sit here until you get it. SURMA: Until I figure it out. JAKE: Until you name every bit of construct in ES3. Should I just tell you? SURMA: Yeah, come on. JAKE: Should I just tell you? Because I wouldn't have got this, either. SURMA: Go on, then. JAKE: Catch. The error-- SURMA: Oh, so try catch was a thing? JAKE: Yes, we had that. We had that in olden days, as well. Thank you very much. But this error identifier is only available in the catch. SURMA: Interesting. OK. JAKE: And so this bit I did know. Or I knew catch had a scope associated with it. But actually, because I'd heard that, it misled me to think that variables would be scoped within it. They're not. [INAUDIBLE] variable in here. SURMA: So then those again would bubble up to the outer function or scope while-- OK. JAKE: The error stays within the catch block. SURMA: OK. JAKE: And the other one, which I will forgive you for not knowing, is with. SURMA: Is that still a thing? JAKE: Well, it was in ES3. I think-- SURMA: That's what I mean. Is it still a thing? JAKE: I think in strict mode, it stops you using it. But don't hold me to that. SURMA: What does with even do? JAKE: Right. What it will do is it will-- SURMA: It's just like a replacement for scope block? Block scope? JAKE: Well, so it will take all of the properties of object and create local variables for them inside the with block, but only inside the with block. So it is, I believe-- and again, don't hold me to this-- I believe it's the only thing in JavaScript where the variables that can exist within it are not deterministically-- you can't figure that out at parse time. I guess the other part is eval. SURMA: Fair. But-- JAKE: And that's why both of these things-- like, if you're using eval, if you use with, a lot of the performance optimizations that engines have just go out the window. Because they can't [INAUDIBLE]. SURMA: The fact that the syntax had to [? gut ?] this, you know, means that it's a thing. JAKE: It is a thing, is a thing. So that's the two things that have a different scope. SURMA: All right. JAKE: But then, right-- oh, yes. Special behavior. Special magic behavior. SURMA: Oh, boy. Oh, is this the hoisting? JAKE: No, this is not the hoisting. The hoisting is-- this was going to be a short video. No, I'm not going to talk about hoisting. People can search for hoisting if they-- SURMA: I think we talked about hoisting once. JAKE: Fine. Good. We'll just put a-- SURMA: It's one of my favorite words. BOTH: Hoisting. JAKE: Hoisting sauce. If you have a global variable with var or function, it does a magic thing in that it will also-- well, it will put it on the global object. SURMA: How is that magic? I thought that's the thing that is the global, right? JAKE: Well, you say that. But that's only because you're used to it, right? It's actually weird. Come on. SURMA: It is weird. JAKE: It's weird. SURMA: But I thought that's just the whole premise of JavaScript, that your global scope is also tied to a specific identifier. But maybe that's just me coming into JavaScript too late, where all these things have already been figured out? JAKE: Well, hold onto that. I would say just as an aside, yeah, so self is referring to the global object. That's what it is in the browser. You also have window. That's only in windows. SURMA: But you're currently talking ES3, right? Because this is already different. JAKE: Oh, no, your global object is self today. Your global object is window if you're in a document. Global is the global in Node. And the new bit is globalThis, which is trying to standardize across all of those. Because it turns out we couldn't standardize on any one of these, because people use it to detect the environment they're running in. SURMA: I thought there was a case where self and window might not be equal. Maybe I'm wrong. That's not. That's not. That's not. JAKE: No. SURMA: That's not. JAKE: I definitely don't know off the top of my head. SURMA: OK. JAKE: So yeah. So this is the magic case. It's weird and magic that stuff in the global goes onto the-- SURMA: Is self still window-- JAKE: Yes. SURMA: In module script tags? JAKE: Yes. SURMA: OK. Then I'm wrong. JAKE: That much I know. So we've got some new stuff. SURMA: We got new stuff. JAKE: New JavaScript stuff arrived. Along with var, we got some new ones, const and let. Which we talked about in the show before. And these have more sensible scoping, shall would say. SURMA: More-- yeah, less unorthodox. JAKE: Specifically block level scoping. So inside this if, as we've already seen, one is going to be thrown into the parent scope, be it a function or a global. Whereas two will only exist inside the if block. SURMA: The if [? scope. ?] JAKE: And same with three. And that's true for while, for do-- SURMA: Pretty much any curly braces, right? JAKE: In fact, you can do that. SURMA: Ah. See, there you go. JAKE: And there you go. And it works. So that's kind of how you think about it. If it's got the curly braces, two and three are going to do the right thing inside there. So I was playing around, and it suddenly occurred to me-- SURMA: Yeah. JAKE: What's going to happen now? SURMA: This should not throw. I think this will work. JAKE: What do you think will happen? SURMA: Because the var one will bubble up to the containing scope, which might be the function of the global scope. And then const one will shadow that, because shadowing is a thing anyway. JAKE: Yeah. No. SURMA: Oh. JAKE: That is not what happens. And genuinely, when I thought about this, I didn't know. And I agree with you. Like runtime, this could be a thing. But this fails at parse time. It sees two identifiers being declared within the same scope, even though var will do something slightly differently. SURMA: All right. JAKE: And it will-- SURMA: So it will actually throw. JAKE: Yes. SURMA: Interesting. JAKE: And I guess it might be down to-- like, if you have const one in a block, you cannot previous to that refer to one in a parent scope. It will tell you, you are trying to use the thing before it is declared. So I think that's where this comes from. SURMA: I see but if I move the var outside the curly braces, then-- JAKE: It's fine. SURMA: That's fine, right? JAKE: [INAUDIBLE]. SURMA: Interesting. OK. JAKE: Yeah. So there we go. That was a pointless piece of information. But it's something I learned while making the slides for this. So I guess, the first part of the question really is, we've kind of seen these vars, we've seen these consts things. But across two script tags, how does they work? SURMA: Yeah. How does it? JAKE: How does they work? One goes on to the global, as we've seen. SURMA: Yeah. I mean, we're pretty sure about one at this point. JAKE: It works. SURMA: Two, it's already slightly a bit more questionable. JAKE: Yes. So you could also do self.one. Fair enough. And yes, the questionable one is two. That was a good sentence to say, wasn't it? The questionable one is two. Questionable-- the one that is questionable is two. No, there's no good way of saying that. SURMA: No. JAKE: Do you know what? I went back and forth on the variable naming here, between just doing a, b, c, and d, or 1, 2, 3, and 4. And I felt like I'd done the right thing. Now I realize-- SURMA: You didn't. JAKE: I did not. OK. It's very confusing. SURMA: Well, it's better than foo, bar, baz. JAKE: So that's what I'd started with, and I ran out. I went, foo, bar, yo, biz, baz-- SURMA: I mean, there's [INAUDIBLE] and [INAUDIBLE].. JAKE: I don't remember. I don't remember after that. SURMA: That's an especially useless tangent. JAKE: So two. SURMA: The thing is, I did the quiz. I looked at the solution. I don't remember. JAKE: Really? Great. Excellent. So when you do const two at the top level, like var it goes on the global scope. It goes in the global scope. SURMA: OK. Cool. JAKE: So this works, because the two scripts share a global scope. Job done. SURMA: So contrary to what I think most people on Twitter believed, a script tag is not equivalent with, like, curly braces. It's not a scope. JAKE: Exactly. Correct. But this is where things get different. SURMA: Right. Yes, I remember now. JAKE: And so, yes. Two does go on the global. In terms of ECMAScript, it is a global. But what it doesn't do is it doesn't do the weird hooking it into the global object sort of thing. SURMA: Because technically the global object is under the actual global context. It seems like. That's how I understood Yang, one of our V8 engineers who wrote an explanation. JAKE: Yes. Yes and sort of. In some ways, the global that one and two exist on are not the same. In some ways they are, in some ways they aren't. Because same again, like, if you did var one equals true and const one equals true, you could think, if they're sitting at a different level, it should all be fine. But it's not. It will stop you from doing that. SURMA: So they're both on the-- JAKE: So it's one global. SURMA: Right. JAKE: Except one-- SURMA: So I guess, then, that actually is magic like you said, that the one gets additionally patched into the global object, which is something else from the global context. JAKE: Yes. There's this kind of objects record thing in ECMAScript, and that's how it works. So yes. So there we go. One works self.one works. Two works. self.two will be undefined. SURMA: It will be undefined. JAKE: So there we go. But-- dun-dun-dun-dun-- what happens here? What changes? SURMA: Well, I did know that module scripts don't bubble up to the global. JAKE: You're sort of right. If you create-- imagine that they're wrapped in a function. SURMA: Right. JAKE: So if you-- SURMA: So if you just have a free floating var in a script module tag, that will not end up on the global context or the global object. JAKE: Correct. So you still have access to the global. Like, you could still access document and blah-blah-blah. SURMA: But if you want to put something on the global, you have to do it manually and explicitly, right? JAKE: Absolutely. SURMA: Right. JAKE: That is true. So that, I guess, takes us to-- SURMA: To this. JAKE: The "quest-eon" from-- SURMA: The "quest-eon"? JAKE: The "quest-eon" from-- I had to teach you. You used to say "quest-eon." It used to wind me up. SURMA: I mean, it's just wrong, isn't it? JAKE: And do you know what? As a teacher, you say that word a lot. SURMA: Yeah. JAKE: And so it was really frustrating. This question. SURMA: All right. So we know now that one and two will be-- that will-- oh. No. They're not-- they know that-- JAKE: Ah. No, let's do the rest of the episode without actually saying proper words. That's nice. Ha. Hm. SURMA: All right. So one and two are on the global context. JAKE: The global context. So-- SURMA: But now these, the look ups also happen on the global context. So this will work. One and two-- JAKE: One works. SURMA: Self.one works. JAKE: Self.one works. SURMA: Two works. Self.two will be undefined. JAKE: Self.two will be undefined for the reasons we did before. Because even though it's in a script module, it accesses it in the usual way. SURMA: That will throw. JAKE: That will absolutely throw. SURMA: Yes. JAKE: I paused to remember. Yes. Because we treat module as if it's wrapped in a function. It's got its own kind of the scope. SURMA: So this will actually be an undeclared variable. JAKE: Undeclared variable. SURMA: While self.three would be still undefined-- JAKE: Would still be undefined. SURMA: Because that's different. That doesn't throw. Looking up-- JAKE: A property is fine. SURMA: Yeah. JAKE: So it would be undefined. Yeah, it wouldn't throw. SURMA: Four, same. JAKE: Would also throw. SURMA: Yeah. JAKE: And that is it. That is how scopes work in JavaScript. SURMA: I mean, you say is like, there, now you understood all the patterns. Like, if you rely on-- [INAUDIBLE] if you rely on variables being passed in between script tags implicitly, probably a bad pattern. JAKE: Well, there are cases you would do this. Because if you're doing a server render thing, but you also want to dump the initial set of data into a script tag, that is somewhere where you will want to do-- SURMA: But I'm saying that, if you want to do that, make it explicit. Write "self.blah-blah-blah equals." JAKE: Oh, interesting. Yeah, OK. You're right. SURMA: Because don't rely on these implicit rules. Because then everybody will look at this and have to think, oh, I don't remember how the details were of these global context scoping rules. JAKE: I would actually agree that. I think the whole thing about-- well, there's a reason why const two doesn't end up on the global object. Because it's weird, right? SURMA: And also, we kind of want to stop the, putting everything on the global object, right? Because it's been kind of polluted over time anyway. JAKE: Yes. SURMA: So let's only make that happen when it's a conscious choice by the developer, to actually write down "self dot [POP] equals"-- then fine. JAKE: And we do see that with future JavaScript, as well-- things like async functions, generators, all of that. They're functions. They still behave like functions. But class behaves more like const and let in that it will be, like, block scoped, and not do the global thing as well. SURMA: Oh, I didn't know that. Interesting. JAKE: It's something I looked up on the train this morning, thinking, someone might ask that. So I'd better know my stuff. You didn't ask that. So I just thought I'd crowbar that little fact so I'd feel, like, fulfilled. SURMA: Right. Did you use all of your knowledge you looked up now? Is there something else you want to sprinkle in? JAKE: That is all the knowledge I had to give you in this episode. Done. SURMA: Thank you very much for this insightful report. Kind of getting used to wearing my glasses for the shoot. And now I'm wondering at what point I can confidently pull off the [? Russell ?] and go like-- JAKE: Yeah, that. Well, that's what I've noticed, actually, with-- because I wear glasses, you know. SURMA: You have the [CLICKING] JAKE: I've got the two things. SURMA: The stripes of doom. JAKE: They're really-- my new glasses are actually really harsh like that. And so I've been thinking, like, if I just keep wearing them, then it will get better.
Info
Channel: Google Chrome Developers
Views: 24,575
Rating: 4.9416666 out of 5
Keywords: javascript, chrome, scope, GDS: Yes;
Id: 5LEuJNLfLN0
Channel Id: undefined
Length: 17min 21sec (1041 seconds)
Published: Thu Aug 01 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.