- What is the reason behind the name 'Closure'
- Actually viewing closures in a debugger
- how to reason about closures while coding
- the most common pitfalls of its use
A Simple Example (bug included)
The simplest way to understand closures is by realizing what problem they are trying to solve. Let's take a simple code example with a counter being incremented 3 times inside a loop.
But inside the loop, something asynchronous is done with the counter. It could be that a server call was made, in this case, let's simply call
setTimeout that will defer it's execution until a timeout occurs:
Some things to bear in mind:
- the variable i exists in the scope of the
closureExamplefunction and is not accessible externally
- while looping through the variable the
console.logstatement is not immediately executed
console/logwill be executed asynchronously 3 times, and only after each timeout of 1 second elapses
- This means that 3 timeouts are set, and then the
closureExamplereturns almost immediately
Which leads us to the main question about this code:
When the anonymous logging function gets executed, how can it have access to the variable 'i'?
The question comes bearing in mind that:
- the variable i was not passed as an argument
- when the
console.log statementgets executed, the
closureExamplefunction has long ended.
So What is a Closure then?
When the logging function is passed to the
To solve this, the engine keeps a link to this variable for later use, and stores that link in a special function scoped execution context.
Such a function with 'memory' about the environment where it was created is simply known as: a Closure.
Why the name Closure then?
Is there any way to See the Closure?
The simplest way is to use the Chrome Developer Tools debugger and set a breakpoint in line 7 of the code snippet above.
When the first timeout gets hit, the closure will show up in the Scope Variables panel of the debugger:
As we can see, the closure is just a simple data structure with links to the variables that the function needs to 'remember', in this case the i variable.
But then, where is the Pitfall?
We could expect that the execution log would show:
counter value is 0 counter value is 1 counter value is 2
But the real execution log is actually:
counter value is 3 counter value is 3 counter value is 3
This is not a bug, it's the way closures work. The logging function is a closure (or has a closure, as the term is used in both ways) containing a reference to the i variable.
This is a reference and not a copy, so what happens is:
- the loop finishes and the i variable value is 3
- only later will the first timeout expire, and the logging function will log the value 3
- the second timeout expires, and the logging function still logs 3, etc.
How to have a different counter value per async operation?
This can be done for example by creating a separate function to trigger the async operation. The following snippet would give the expected result:
This works because when calling
asyncOperation a copy is made of the counter value, and the logging will 'close over' that copied value.
This means each invocation of the logging function will see a different variable with values 0, 1, 2.
They can be a convenient way to reduce the number of parameters passed to a function.
But mostly the fact that the closed variables are inaccessible
But beware of the pitfall: closures keep references and not copies (even of primitive values), so make sure that that is really the intended logic.
Want to Get Started With Angular?
If you are getting started with Angular, you might be interested in this YouTube course:
Looking for Angular Learning Resources?
If you want to learn more about Angular, have a look at the Angular for Beginners Course:
Other posts on Angular
If you enjoyed this post, here some other popular posts on our blog:
- Angular Router - Extended Guided Tour, Avoid Common Pitfalls
- Angular Components - The Fundamentals
- How to run Angular in Production Today
- How to build Angular apps using Observable Data Services - Pitfalls to avoid
- Introduction to Angular Forms - Template Driven, Model Driven or In-Between
- Angular Universal In Practice - How to build SEO Friendly Single Page Apps with Angular
- How does Angular Change Detection Really Work?