The concept of JS Closure

In JavaScript, the scripts as a whole have an associated object known as the Lexical Environment.

Note that I just write my image of js Closure.

I won’t guarantee that it is the actual code it works in js.

To make is easy to understand it, let’s say, we see Lexical Environment as Object: like that

let someVariable = 100

If we declare global variable, It means that in the way below:

GlobalEnvironment {
  EnvironmentRecord {
  someVariable: 100,
  // ...other property goes on 
}
}

That is one part of JS Lexical Environment works.

Another is to give us a reference to the outer Lexical Environment.

We see that when we use functions in JS.

Every function in JS creates its lexical Environment.

Inner Lexical Environment has the reference to the outer ones from the point it refer them.

//Here is the example of closure with function
function makeCounter(n) {
  let counter = n;
  return () => ++count;
}

The inner function of makeCounter have the reference to the counter variable, which is outside of inner.

On top of that, Inner function also creates its own environments.

If we call that function, having the same reference, it updates its counter.

let counter = makeCounter(1);
counter() // 2
counter() // 3
counter() // 4

And one thing to note is that a new function environment is created each time they run.

If we make another counter, it create another environment, its reference to anew one.

let count = makeCounter(1);
let newCount = makeCounter(1);
counter() // 2
counter() // 3
counter() // 4
// It doesn't share the same environment as count variable. 
newCount() //2

To see how it works from the environment record.

EnvironmentOfCount {
  EnvironmentRecord {
    count: 1,
innerFunction: {
      // inner function has its own count after first called
// every call updates its counter, holding its own reference
// to innerFunction's count.
      count: count++  
}
    // ...other property goes on 
}
}
// And another called makeCounter creates a new environment
EnvironmentOfNewCount {
// ...
}

Not only function , but block scope also creates Lexical Environment.

{
let someVariable = 100;
}
console.log(someVariable)// Identifier undefined

There is one exception, when is comes to closure.

We should take care of when we use setTimeout, since all functions in setTimeout is executed in the global scope.

Let’s see the example:

let obj = {
  a: 100,
b: 200,
c: "someComment",
d: () => setTimeout(() => console.log(this.a, this.b), 1000)
};

If we call it d method in obj.

obj.d():
// undefined, undefined

it doesn’t work as we might expect. It’s because this in setTimeout refers to the global this(window in browser, or based on the context).

Conclusion

Basically, I pay attention to the context where the variable is declared.

The most important part in closure is, each time function run, a new environments are created.