- 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 it's 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 2 ?
If you are getting started with Angular 2, you might be interested in this YouTube course:
Looking for Angular 2 Learning Resources ?
Check our top 10 list of Angular 2 Resources:
Other posts on Angular 2
If you enjoyed this post, here some other popular posts on our blog:
- Angular 2 Router - Extended Guided Tour, Avoid Common Pitfalls
- Angular 2 Components - The Fundamentals
- How to run Angular 2 in Production Today
- How to build Angular 2 apps using Observable Data Services - Pitfalls to avoid
- Introduction to Angular 2 Forms - Template Driven, Model Driven or In-Between
- Angular Universal In Practice - How to build SEO Friendly Single Page Apps with Angular 2
- How does Angular 2 Change Detection Really Work ?