almost 3 years ago Syntax Podcast
JavaScript Closures & Scope Explained
- 02:33 Introduction to local scope
- 03:00 Global scope in JS
- 04:40 Local vs global scope
- 06:06 let/const vs var for block scoping
- 07:31 Block scope syntax
- 11:01 Lexical vs dynamic scoping
- 12:03 Function scope creates closure
- 13:11 Inner functions maintain outer scopes
- 14:35 Closures allow inner functions to access outer scopes
- 16:06 Dynamic scoping is uncommon in modern languages
- 17:13 Closure for private variables
- 17:55 Closure example with Svelte
- 19:15 Modules use closure
- 20:18 Closure for caching
- 21:59 Closure for reusable logger
- 23:20 Closures used more in functional programming
Closure for caching
Wes Bos
what the use case is for me to even use this type of thing. So One more example I have is if you want to create like a logger function like an object is not a scope. But if you have an if statement or if you have a function or you have a case switch or any of that, called And every single time
Wes Bos
show name, the syntax show number, the date, and any guests that we have.
Wes Bos
Promises in a single way, but it kind of still works the same way. I'll link up the
Scott Tolinski
Promises.
Scott Tolinski
I get closures. You know?
Scott Tolinski
In your development career, Yeah. Which is it's so funny because, again, it does seem like such a complex thing.
Scott Tolinski
But it it for some reason, I don't know what it is. It's one of those topics that just sparks a lot of confusion for some reason, and it I'm not immune to that as well. I until I, like, had to
Scott Tolinski
write these types of things, I I had no idea
Scott Tolinski
And even here, you might be listening to this and thinking, like, I don't have any use for this, and that's totally fine.
Scott Tolinski
And it's not that big of a deal.
Wes Bos
I have a couple more examples here. Asynchronous work is not as popular. It was very popular in the callback world we have this idea of a closure. So when you create a function, that function has scope.
Wes Bos
The fact after they've died.
Transcript
Announcer
soft skill, web development, the hastiest, the craziest, the tastiest TS Webb development
Wes Bos
that you might not totally understand.
Scott Tolinski
It sounds interesting. It sounds maybe perhaps confusing. So we're gonna be talking all about what closures are, how to reason about them and and what what exactly like, why are they something that people even talk about, or why are they interesting? My name is Scott Tolinski. I'm a developer from Denver, and with me as always is Wes Moss. What's up, Wes? Hey.
Wes Bos
I did it in my beginner JavaScript course.
Announcer
Monday. Mon Monday. Hey. Open wide dev fans. Get ready to stuff your face with JavaScript, CSS, node modules, barbecue tips, get workflow, breakdancing,
Scott Tolinski
it's it's not a ton of fun. So we're gonna try to make it fun.
Scott Tolinski
Perhaps we will bring in a sandwich metaphor. I don't think so. But, you know, who knows? for the entirety of the the browser scope anywhere in your application
Scott Tolinski
anywhere in your application.
Wes Bos
I've done it a couple times when when teaching and whatnot, and it's always one of those, like,
Scott Tolinski
You define a variable on the global scope. You can reference that variable
Scott Tolinski
like, macro to microscope that we have. So for instance, we have a global scope, and that is everything that you can access globally.
Announcer
treats coming in hot. Here is Wes, Barracuda,
Scott Tolinski
scope in scoping, which is, like, always one of those things that I I feel like Causes people's eyes to glaze over a bit when they're learning about scoping or,
Scott Tolinski
ghee. Welcome
Scott Tolinski
closures are one of those things in JavaScript that have kind of a weird name. If you're coming to JavaScript script or programming. You're new to this stuff. You see the word closure.
Scott Tolinski
to Syndax.
Wes Bos
Boss, and Scott and then inside of that function, you return another function it's going to reach into the closure expanding its scope per se Yep.
Wes Bos
Yeah. Explaining closures. And, like, I've I've done the, like, explained closures.
Scott Tolinski
And,
Scott Tolinski
On this Monday, hasty treat, we're gonna be talking about closures. Now,
Scott Tolinski
Yeah. And it doesn't help that it goes along with, in general,
Scott Tolinski
With Wes, you never know if the sandwich metaphor is coming. So let's talk about scope overall. 1st quickly, so the different types of,
Introduction to local scope
Scott Tolinski
it's coming up with a value because it's been defined somewhere else. So
Scott Tolinski
used ways in JavaScript to limit the scope in which we're currently working in instead of having this giant accepts some things.
Scott Tolinski
We
Scott Tolinski
typically,
Scott Tolinski
In the browser,
Scott Tolinski
global scope full of everything.
Scott Tolinski
have for a full archive of all of our shows,
Closure for reusable logger
Wes Bos
In its closure scope, and it can console log the show name and the show number and the guests and all of that data. And you don't have to, like, Carry around or reconstruct the entire logger every time. You can simply just say log page loaded, and then the console log will look like variables are determined To find exactly what it's looking for. So functions make Enclosing scope.
Wes Bos
from that you can return, like, a log function where you can just say log Peace.
Wes Bos
Loading And the way that JavaScript works is if you are trying to reference a variable So it's sometimes nice to just tuck away complexity into its own function and then return a new function They still have their own scope, and they still are It's literally looking are function scoped,
Scott Tolinski
Yeah. But why don't you just use a class for some of these things? Right?
Scott Tolinski
You can call at any time, and it still has access to that data. So another thing to note that I don't know if you you specifically mention because people might be listening to this and be wondering, like,
Wes Bos
law page loaded for episode 4 you do a little bit of math inside of there. You are dog years old. You create a variable of age, And then you inject it into the sentence. So you just you just made a variable quickly, threw it into a string, and now you're done with that. So the variables that were created inside of that function to do the work and then you return hello, s, or like, if you have 1 file and you want to be able to access it in another file without importing or exporting or passing or anything like that, you can stick it on Global This and you'll have it available to you. But Not too, too much. We have had this
Wes Bos
94 titled Blah Blah Blah with guests,
Scott Tolinski
And that's really, really one of the the pieces is that the closures are used less in object oriented programming, and they're more associated with, like,
Wes Bos
And any time we do anything, we load a page, we update something, we delete it.
Scott Tolinski
So if you're you're out there and you're using classes and stuff, you you might not run into this as much. Yeah. Because a class allows you just to stick that stuff
Scott Tolinski
functional programming topics.
Wes Bos
Scott and Wes.
let/const vs var for block scoping
Scott Tolinski
I posted a little little syntax for just a a JavaScript block. And and it's funny. I almost never use straight block syntax.
Wes Bos
open bracket, close curly bracket, and write some code in there, and it creates a block. Exactly. So we have global scope, we have local scope, and then you have this thing called enclosing scope,
Scott Tolinski
Do you ever use that where you're just using the curly brackets without anything else, like an issue? Or There are times
Scott Tolinski
to use This also says,
Scott Tolinski
Let or const over var nowadays
Wes Bos
And in dev tools, when you create a variable, you're creating a global variable. So if you wanna rerun that code, it says, ah, you already created that variable. Chrome DevTools will allow you to override it because it realizes you're doing, like, a iterative process, but not in Firefox. So if you just wrap a set of curly brackets around your code, And when you call that function, the initial data And then inside of that function, let's say you have a variable called name equals west, const name equals west.
Scott Tolinski
because it can be a little mysterious if you're assigning a variable inside
Wes Bos
get it, but it is a nice way to or if you have you should not do that.
Wes Bos
The only time I use that is in dev tools file, if it's not inside of a function or it's not inside of an if statement or anything like that, Check it out if you like this show. You can buy it. It's really good.
Scott Tolinski
if you know that, like, a block is containing
Scott Tolinski
to make its own scope. Yeah. And if you don't know what I'm talking about, you can just do
Scott Tolinski
the variable itself. So, things aren't meant to be put too much in the global scope. If you pollute the global scope too much, You're gonna have weird things where you're using a variable, and all of a sudden, a funk or having a function directly in the use enhance action. The use enhance action,
Scott Tolinski
of a block scope, and then you're accessing it outside of a block. And you're like, why did this? You know, why is this using the the value that it is? And it's more predictable
Local vs global scope
Wes Bos
go willy nilly making variables meaning that inside of that function,
Wes Bos
are creating their own scope, meaning variables created inside And the benefit of that is that it It's creating what's called the closure. Right? We'll we'll talk about in a second. We should talk real quickly is that JavaScript is lexically scoped. You may this is the an interview question. Right? Some programming languages are dynamically scoped, and most programming languages are lexically scoped, So the browser knows, okay.
Wes Bos
those curly brackets
Wes Bos
when you have little code fences. I like to think of the curly brackets. Fences. Oh. Code fences. Yeah. Curly brackets in JavaScript keep your variables in. That's what they're there for. Right? And every time you have a set of curly brackets, And the second, which is the name of the game, and it just says your hockey score is 1. Your hockey score is 2. Then you can go ahead and create another one. Create game soccer.
Wes Bos
outside of the gates of your curly brackets. Right? Now that we understand scope,
Wes Bos
except for an object, inside of a scope, JavaScript will first check
Wes Bos
functions, literally anything with curly brackets.
Wes Bos
So let's go with scope. Then we also have what's called local scope. So you've just created a scope. Right. And you can't access the variables inside of that because you've And inside of the create game, you create a score are not available if that is true, then it finds it.
Wes Bos
And that's really nice because you can
Wes Bos
is created
Wes Bos
Local scope is variables that are available inside of a block.
Wes Bos
So a block in JavaScript
Inner functions maintain outer scopes
Wes Bos
So really. So you you can't, hockey. So you're passing in is closed and the variables with the new data.
Wes Bos
of another function, let's call that an inner function, can still access the outer variable.
Wes Bos
If you put a function inside past Those 2 things have nothing to do with each other unless you explicitly pass the value into it and and introduce that value into the scope.
Wes Bos
So that inner function
Wes Bos
the very once the function is done running, the variables are garbage collected. But what happens if the inner function they're not going to leak out and just have some random thing. Var variables Create.
Wes Bos
If you talk about generating You can use a factory function and you say create logger, pass it the whole show, or or a for statement inner function unless you explicitly import and export them. And that is a super handy Right? And you can just store it in there. And with the function, you can't just stick the stuff anywhere. So you have to sort of create this idea of closure. So, yeah, you're right.
Wes Bos
where the variable is inaccessible to you because the function is done, But that internal you you say, like, const my name equals wes, and then you run the function called but its own scope
Wes Bos
being run. It's closed. But You've created a closure,
Wes Bos
What happens to that variable? I just said on the list for probably a couple of months now That is is not run yet, but it's just you've created a you dynamically created a function says, okay. Here it is. You can go ahead and call this later.
Wes Bos
that that inner function being able to access a variable
Wes Bos
And you've sort of created this little if you're doing As if you were doing functional work. Word. Alright.
Wes Bos
a function
Wes Bos
that's a basic function being to make global variables these days. It used to be you had a script tag, and you load in the script tag. Any variable that you declared inside of that JavaScript or
Dynamic scoping is uncommon in modern languages
Wes Bos
course notes for free on my website, is private variables. So you have a function called create game, It takes in a game name, so tricky things to to sort of do because
Wes Bos
That is set to 0. And every single time that you run that return function, where into its parent function where the code was written, the scope is determined by where the variables are written in your code, not where it's run, and that's most I would say most programming language. I wonder what languages are dynamically scoped. Oh, I'll I'll look that up while you take the next set section. So closures.
Wes Bos
and then you return a function called win.
Wes Bos
You call that win function. It will increment
Wes Bos
So let's talk about some examples of where a closure might be handy. All right. So one example is and I'll link up the actual code for this from my website, as I have all my beginner JavaScript
Wes Bos
variable that's called let score equals 0,
Wes Bos
basketball. Right? not where the variable was defined. So if you have a function that internally that you can still access and reference and update and return
Wes Bos
and you're creating a score variable
Closure example with Svelte
Scott Tolinski
the
Scott Tolinski
the function for me with the properties and the variables and the scope that I needed each time
Wes Bos
aren't a function per se.
Scott Tolinski
forms inside of SvelteKit
Wes Bos
when the thing is loaded, but What is returned does not. It doesn't run the function immediately. It returns you a new function that is sort of preloaded or bound So you have a function called say hello.
Wes Bos
Another example of closures is I think this is probably the most common one is modules. Modules and then Because I want to re rerun the same code over and over again.
Scott Tolinski
pass in your own variables to this thing. You couldn't have your own,
Scott Tolinski
having
Scott Tolinski
is by
Wes Bos
you. You have to pass
Scott Tolinski
essentially your own function each time this was going to be run, so I created a factory function that created
Scott Tolinski
enhanced
Scott Tolinski
So anytime my enhancing to be run, it wouldn't just call a function. It would create the function
Closures allow inner functions to access outer scopes
Scott Tolinski
Offer the ability to do dynamic or lexical scoping.
Scott Tolinski
but it does seem like several languages
Scott Tolinski
It says early versions of lisp,
Scott Tolinski
Some versions of Pearl have a keyword for dynamically scoped with the local keyword.
Scott Tolinski
hex. So almost nothing. TCL. Yeah. Almost nothing. Languages that you have not heard of or almost always, like, older kind of programming concepts or languages.
Scott Tolinski
bash and other shell scripts. But when I dug into it, I did find a Stack Overflow post where somebody says there's no
Scott Tolinski
not super common as a main feature in modern languages, when you will have this moment, and you're like, it all makes sense now. I understand,
Scott Tolinski
four
Scott Tolinski
Emax lisp.
Wes Bos
lives that are gone, what was it,
Wes Bos
the value from there. So that is what is referred to as a closure because the outer function has been closed over, and then run that function. That that was a really good example because let me reach outside of my scope and see, does this exist in the module scope, right? So you're essentially creating a
Scott Tolinski
there is no dynamic nor static scope in bash. So I it it's I you know, it's it's not, like, super crystal clear. It's Mhmm. Noble
Wes Bos
on in memory. It's not going to be garbage collected because something is still referencing those variables internally.
Wes Bos
neat little nesting spot for variables
Function scope creates closure
Wes Bos
And inside of that function, you say const sentence equals hello, Wes, 20 minute radius would be. Like, it just keeps going up a level, display name.
Wes Bos
So I'm just going to throw it out because there's no sense in keeping it around because eventually we're going to run out of memory on the user's computer. Right? That's what garbage collection is.
Wes Bos
variables inside of that function are created.
Wes Bos
They're garbage collected.
Wes Bos
When the function is done running, that function
Modules use closure
Wes Bos
in Node. Js or anything like that, of curly brackets and say, hey. I'm looking for a name variable. Is there any variable because that towards this variable.
Wes Bos
and whether that is a counter for how many times a function has run which is So lexically scoped means the score variable over and over again. So what you can do is you say like const hockey game equals create game
Wes Bos
is is maintaining state from the last time that it ran, and it says, alright. Well, if I already generated this image, and see what that actual value is.
Wes Bos
if you create a variable that is outside of your route handler
Wes Bos
Or my case, I often will create a cache and they are garbage collected, meaning that the browser put them into memory real quick, instead of, like, let's say if I wanted to console log the syntax passed around and maintained
Wes Bos
into the module scope, which I can't throw those out just yet because something is still pointing towards them. So dynamic scoping is really like a route handler what closures are. Essentially, they are just scope
Global scope in JS
Wes Bos
So if you want to stick something on Global Scope for whatever reason, Then you've just created a global variable. And that's why you
Wes Bos
there is a variable called global this. It's even available in the browser.
Wes Bos
global this, like sort of a closure in themselves.
Wes Bos
can type a variable in a script tag and then go into your dev tools and type it in in the console for 2 things, the score, which you can then update. It's a private variable.
Scott Tolinski
without having to even import or reference anything. It's just available to you. That's on the global scope.
Wes Bos
other platform, It's it's actually really hard you've now created 2 scopes. Right? You have your function scope, and then you have your if statement scope.
Scott Tolinski
you have like, the window is a global scope. Right? You can access things For the window, Yeah. And this is one of the reasons why people often say
Wes Bos
you can use the variable The handler will reach outside of the function scope disappear.
Wes Bos
In other platforms,
Wes Bos
So it's pretty tricky to actually do that anymore because did the work and then it closes. Alright. Well, like, literally nothing else is still pointing and of those a parent function
Wes Bos
camel case, and that will give you access in Node. Js. That will give you
Block scope syntax
Scott Tolinski
within your household. Is there any cheese within your household? And then maybe the next scope out would be, is there any cheese in my 20 minute radius?
Wes Bos
an immediately invoked function expression, b, You gotta have, like, real world examples of, like, when you might use that. Otherwise, it's just a, like, bizarre concept which is basically just a function that immediately you put parentheses on the end and it calls itself.
Wes Bos
say hello.
Scott Tolinski
you could think, like, 1 scope could be the bread. You'd say, is there any cheese in here, and it's checking between the 2 pieces of bread first. Yeah. Well, there's no cheese in here.
Wes Bos
by where the code is defined, not where it's run, meaning that we go through the whole example of just going up the scope chain.
Wes Bos
if you have curly brackets. Let and cons variables
Wes Bos
import or an export or you load something in via type of module, it's a, it's scarier. It sounds scarier than it actually is. And even though modules when you have multiple scopes nested inside of each other. So That's the reference it uses, but it will keep going up scope levels until it finds what it's looking for. And eventually you're going to hit global scope. And if it's not there, then
Wes Bos
If so, that's the one I want. If not, it says, alright, folks.
Wes Bos
side of this if statement or inside of this for loop or inside of this scope named name?
Wes Bos
the local gates tricky bits closures from my website. You can read through it. Just get a couple more examples in there to totally understand it. But hopefully that gives you a good example of
Scott Tolinski
Goes kinda up the tree, every set of curly brackets. So if we wanted to to bring in the sandwich metaphor here, the the one that I did for the Svelte site is for a Svelte action. The way that you can do, Head on over to syntax.fm enhance was run.
Wes Bos
If you have an if statement can still go up the scope chain like we were talking about earlier. Right? So little closure there where you put the cache outside of the handler and you can reuse it from function call to function call.
Wes Bos
Probably the most popular scope that you're not used to is module scope. So every single time is still referencing a variable from the outer function, a variable
Scott Tolinski
And then maybe the next scope out would be, However, I I found that you couldn't necessarily
Wes Bos
will not leak outside.
Wes Bos
I didn't find what I wanted. I'm gonna go one level up. So that goes one level up to the function scope and says, hey, any variables here named name? And inside of a loop or anything like that. And you know that there is no code before or after it that you are going to be accidentally overwriting feature of modules because you're not accidentally creating all this Global scope. You don't have to. In the past, we used to have create what's called an IFFI, We are mostly all using modules. Module we'll talk about that in just a second, but modules have their own scope. In Node. Js land, There is in pretty much every and let and const are block scope, meaning that if statements, for loops, a module, meaning that variables created inside of that module page. And then
Wes Bos
you have a hockey, soccer,
Wes Bos
is
Wes Bos
JavaScript file itself where a function could run, but you have to wait a number second. It's it's not as popular anymore now that we have that variable exists nowhere. So the scope lookup So if you have like a serverless function
Closures used more in functional programming
Scott Tolinski
And don't forget to subscribe in your podcast player or drop a review if you like this show.
Wes Bos
on the class itself.
Wes Bos
on class methods, but not nearly as much and that is what is referred to as a closure, meaning that You've created this ominous space you're kind of pooched because accesses something called name,
Wes Bos
That is a very good use case. You still will run into closure use cases that runs immediately, for saving data in my OG images I talked about earlier.
Closure for private variables
Wes Bos
a function that is sort of preset with a bunch of data. And even Scott made a generator function in the
Wes Bos
They're often called factory functions, from the outer function, function has been passed the show earlier, it has access to the entire show
Wes Bos
You can say soccer win, right? And it will say your soccer score is 1. Your soccer score is 2. So that is a nice way to sort of like where you are you can return it to call it later. Right? So you can have
Lexical vs dynamic scoping
Wes Bos
Right above that function, They're not available to other files that can be the sorry. Factory function. Do you wanna explain the one that you didn't in our our Svelte site? Yeah. Well so That's it for today. Hopefully, you enjoyed that. We will catch you later.