JavaScript Advanced: Closures, Async and Modules
Scope and Closures
In this lesson you will
- Explain global, function and block scope
- Describe what a closure is
- Use closures for private state and avoid the loop pitfall
Introduction
Closures have a reputation for being hard. They are not: they are a natural result of two simple facts. A function can use variables from the place where it was written, and it keeps them even after that place has finished running. Understanding this unlocks a huge part of modern JavaScript.
Scope: where a variable can be seen
Scope is the area of code where a variable is visible.
- Global scope: visible everywhere.
- Function scope: visible only inside the function.
- Block scope: variables made with
letandconstare visible only inside the nearest{ }.
typeof inner is undefined outside its block, because the block-scoped variable does not exist there.
Quick quiz
Where is a variable declared with const inside an if block visible?
Lexical scope
A function can see the variables of the scope where it was written, plus every scope around that. This is called lexical scope. JavaScript looks for a name in the current scope, then the next one out, and so on.
What is a closure?
A closure is a function together with the variables it remembers from where it was created.
makeCounter finished running long ago, yet the returned function still has count. Each call to makeCounter creates its own private count, so a and b do not interfere. Nothing outside can reach count directly.
Closures for private data
Because the variable cannot be touched from outside, closures give you privacy.
account.balance is undefined. The balance can only be changed through the functions you provide.
Quick quiz
What does a closure let a function do?
The classic loop pitfall
With var, there is only one shared variable for the whole loop, so all the callbacks see its final value. With let, every round gets its own copy.
The var loop prints 3 three times, because by the time the timers fire, i is 3. The let loop prints 0, 1, 2. This is one more reason to forget var exists.
Try it yourself
Write makeMultiplier(factor) that returns a function. The returned function multiplies any number by factor. Then make double and triple and test them.
Summary
- Scope decides where a variable is visible.
letandconstare block scoped. - Lexical scope: a function sees the scope where it was written.
- A closure is a function plus its remembered variables. It enables private state.
- Prefer
letin loops to avoid the shared-variable trap.
Lesson complete
+20 XP
Nice work. Keep going while it is fresh.
Sources and further reading