2020-04-29

A visual way to learn Closure

Disclaimer

This article is originally based on my understanding of this concept. No guarantee on the accuracy.😅

The closure is a kind of intimidating concept for people new to javascript.
I think it’s necessary to clarify some concept of execution context (EC) and scope before approaching ‘closure’ itself.

  • Javascript has 3 types of scope (after ES6)

    • block scope

      1
      2
      3
      4
      {
      let a = 0;
      }
      console.log(a) // ReferenceError: a is not defined
    • Function scope

    • Global scope

whenever you’re trying to call/use a variable, the engine would find it along the scope chain.

If the engine detects that a variable would not be called after the function execution context was removed from the call stack, it would junk the variable (garbage collecting) and free the memory.

  • The [[scope]] is determined during function declarartion.

    All code is executed in their execution context: global EC or function EC.

    EC can be abstracted as an object which includes variable object, scope chain, and this value.

  • closure-Page-2

  • Whenever a function is called, its EC would be pushed to the top of the call stack. And all the VO are activated as activation objects. When all the code inside the function is executed or returned, the EC was destroyed. Next time if the same function is called again, a new EC would be created.

  • The function EC has two phases: creation phase and execution phase.

  • The creation phase is when the VO and ‘this’ are created, and the scope chain is initialed by [[scope]]

  • The execution phase is when the value of each object/variable is assigned and determined.

closure

A classic interview question:

1
2
3
4
5
for (var i=1; i<=2; i++) {
setTimeout(function(){
console.log(i);
}, i );
}

Expected: 0,1,2

Print: 3,3,3

Some ways to fix this:
1
2
3
4
5
6
7
8
for (var i=1; i<=2; i++) {
(function outer(){
let j =i; //👈 closure
setTimeout(function timer (){
console.log(j);
}, j );
})();
}
closure-Page-4
1
2
3
4
5
6
7
8
for (var i=1; i<=2; i++) {
(function outer (j){
setTimeout(function timer(){
console.log(j);
}, j );
}
)(i); //passing the global scope value into the function and immedeiately invoke it
}
  • employing block scope
1
2
3
4
5
for (let i = 0; i <= 2; i++) {
setTimeout(function inner() {
console.log(i)
}, i);
}
closure-Page-3
1
2
3
4
for (let i=1; i<=2; i++) {
setTimeout(console.log(i);//an IIFE function
, i );
}
Application of the concept of closure
  • Singleton Design Pattern
1
2
3
4
5
6
7
8
9
10
11
12
13
14
var Logger = (function () {
var instance = null; //👈

return function Looger() {

if (!instance) {
instance = this;
}
return instance;
}
})()
var a = new Logger();
var b = new Logger();
a === b; //true
  • Private property in constructor function

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function Count() {
    let n = 1; //👈
    this.sum = function () {
    console.log(++n);
    };
    }

    let a = new Count();
    a.sum();

Reference:

Javascript You Don’t Konw

Professional JavaScript for Web Developers