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.