Understanding Javascript Scopes and Closures
When thinking about scopes, you can think about your house.
Scopes as we know it in the real world is the same with Javascript. When thinking about scopes, we can think about our house. Every thing has its own scope. We use kitchen knives in the kitchen along with dishwashing liquid and sponge. Shower’s scope is in the bathroom. Bed in the bedroom, dining table in the dining room. You know where this goes.
All you have to think about to understand scopes is this:
You can find every tool, material, object that you need at a specific area of your house.
In other words, you can find every variable (thing) at a specific scope (area).
Let’s talk about the code. In the kitchen area (lines 1 to 4), there is our bread knife. We declared bread knife inside the kitchen area. Thus when we tried to find the bread knife in our bedroom (lines 6 to 8), we couldn’t find it. The scope of bread knife is only within our kitchen and not in the bedroom. Unless you hide a bread knife under your pillow.
Why do wee need to understand scopes?
Scope defines the rules on how we can use breadKnife. If we break the rules, we bump into errors (like ReferenceError). Also, if we don’t understand the rules, we could misuse them.
How is a scope determined?
So how are the rules created within the house? One word. Declaration. When you bought that bread knife, you were firm in your head.
I declare that one can only use this bread knife in the kitchen!
Well, same with our dearest Javascript. All we have to do is declare out loud! We could declare either a variable or a function.
To spot the declarations, find these two keywords: var and function. Once you find them, ask yourself:
Where was this variable/function declared?
Let’s run through all the declarations in the code:
- function kitchen (line 1) — nothing enclosing it (we call it global)
- var breadKnife (line 2) — in kitchen
- function sink (line 4) — in kitchen
- var dishwashingLiquid (line 5) — in sink
And there my friend, you deciphered the scope (rules) on where we can use each variable/function!
Now, let me ask you something. Can you use the dishwashingLiquid outside the sink? If you’re not sure, you could run the code below:
If you’re on your desktop browser
- Go to Developer Tools (for Chrome, shortcut is F12)
- 2. Click Sources tab and type-in the code
Spoiler alert! Running the code will result to:
ReferenceError: dishwashingLiquid is not defined
We declared dishwashingLiquid inside sink (line 5). So, we can only use it inside the curly braces of sink. That is the rule.
Another food-for-thought. Can you use the sink outside the kitchen? Again, if you’re not sure, run this code:
Spoiler alert! Running the code will result to:
ReferenceError: sink is not defined
We declared sink inside kitchen (line 4). So, we can only use it inside the curly braces of kitchen.
By the way, there’s a term for this and it’s called lexical scope. This is when the engine knows the scope of a variable/function based on where we (the author) declared it. The opposite of this is dynamic scope which we won’t tackle here to keep us both sane.
Now, let’s step up our game.
How about blocks?
A block is the space between any opening and closing curly braces other than those of a function’s.
So, what if we declare variables inside them?
Try this one out:
We’re trying to eat some dessert here at line 3. Inside the scope of hungriness, that’s where we want to eat.
But what if I eat outside hungriness, like this?
This should return an error, right?
Lo and behold! You can still eat that dessert outside your hungriness. It was surprising to find out that Javascript allows this. Because this isn’t common in other languages.
Why is it allowed?
The basic structure of Javascript is functions. Keeping that in mind, scopes are function-based and not block-based.
This was true until ES6 was out, introducing us to another way of declaring variables.
We only changed var to let at line 2 and it made all the difference. Now you cannot eat outside your hungriness. It’s for your own good, sorry.
Using let in our variable declarations will give it a scope within the nearest curly braces. In this case, it’s between the opening curly brace at line 1and closing curly brace at line 3.
let has a sibling named const which we can also use for this intention. Difference between let and const would be for another article.
Let’s step up our game one last time!
How about closures?
Closure is everywhere in Javascript. It’s funny how this somewhat relates to a concept in meditation. Closure is like the blue sky. It is always there. We only get caught up with the clouds passing by forgetting the blue sky.
Anyway, what do I mean?
In the past examples, we’ve been using it without us knowing it. Now let’s spot some closures!
Two words to remember closures. Inner function. In this code we used to understand scopes, we had a function within a function. That’s the sink within our kitchen. And yes, sink is a closure!
We could understand closures only if we understand scopes.
So, let’s recall scopes for a second:
We declared breadKnife inside the kitchen. sink is also inside the kitchen. Thus we can also use breadKnife inside the sink. I don’t know, it could be after getting dirty slicing breads!
Let’s make this more interesting.
What if we use the sink outside the kitchen?
Will sink still remember it can use the breadKnife?
We introduced a return statement here containing the function sink. This means that we permit the outside world to use the sink of our kitchen.
Now that our kitchen sink is available to the world, let’s get to business! We made a function call — kitchen() and assign it to some variable myKitchen (line 14). From there on, we can use sink (line 15).
Guess what? sink remembers which things it can use. That is the power of closures! A closure encloses not only the variables/functions declared inside it. But as well as the variables/functions it can use!
sink remembers that it can use the breadKnife!
If we grasp this concept, we could leverage closures in our code. Like we did here, the world didn’t need to know what’s going on inside our sink. (That we washed a dirty breadKnife, if you like keeping secrets like this.)
In Javascript, closures are everywhere. You just have to look.
