Speaking of closures, really it is very easy to let a novice programmers make confused concept, in fact, my own understanding of the closure is very shallow, I be a pragmatic person at the same time, baidu’s the article inside the obscure concept looks really, it’s easy to let the man’s head is big, always is very dry to a has the right to access another function within the scope of functions is the closure, Closures can be written in a variety of ways, which can be confusing for beginners, so I’m going to try to explain my understanding of closures in the simplest way possible, as well as some of the simple scenarios I have in mind.

First of all, let’s forget about the “ghost closure”. Don’t write a closure according to the formula, because each author may write a slightly different closure, we just need to treat it as a normal JS function, which may be easier to understand.

Let’s start with a super simple function

function counter() { var count = 0; count ++; return count; } counter(); // return 1 counter(); // return 1 counter(); / / returns 1Copy the code

This method is believed that everyone can understand it, if not, it is recommended to learn JavaScript from scratch… Here I call the counter() method three times, and each time I return 1, because every time I call this method I re-enter the function and execute from top to bottom, the count variable is reassigned to 0, so I get 1 every time.

Now let’s upgrade the requirements. What if we want the value of count to accumulate with each call to the counter() method?

var count = 0; function counter() { count++; return count } counter(); // return 1 counter(); // return 2 counter(); / / return 3Copy the code

Set count to the global variable, and then evaluate count in the Couter function, this time we get 123. In fact, as we learned from JavaScript basics, global variables are executed globally, and changing them anywhere in the world takes effect immediately. Similarly, the next time a global variable is changed, it’s not its initial value but the last value it changed. Let’s upgrade this example again:

var count = 0; function counter() { count++; return count; If (count >= 0) {counter()} counter() // returns 3Copy the code

As you can see from the above example, the nature of a global variable is that its state is globally shared, in general, globally accessible & globally modifiable, no matter where or in what scope.

Is it the perfect solution to our needs? Yes, that’s true, but the downside of this approach is too obvious. Why should we avoid declaring global variables as much as possible? Reason is really too much, can be arbitrary change global data, and then the changes in front of will directly affect the results of the subsequent code, if you have many places in the code to use global variables and parallel, asynchronous calls, will result in too many unpredictable errors, so no matter what time, we should try to reduce the global variable definition!

Now let’s update our code again. Since the global variable has so many shortcomings, how about we make it a local variable?

{ var count = 0; function counter() { count += 1; return count; }}Copy the code

At this point, the prototype of a closure is basically in place. Remember, to get a real closure, you need to do two things in addition to the code above: 1. Convert this code block to a function. 2. Use the counter function as the return value of the external function. Something like this:

function fn() { var count = 0 function counter() { count += 1; return count; } return counter; } var getCounter = fn(); getCounter(); // return 1 getCounter(); // return 2 getCounter(); / / return 3Copy the code

A standard closure has been written, and although you may not be quite sure why this is done, don’t worry, I will soon explain the implementation principle of closures in the most popular way.

Let’s compare this closure to the error example we originally wrote:

Function counter() {var count = 0; count ++; return count; } counter(); // return 1 counter(); // return 1 counter(); / / return 1 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- line -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- / / closure function fn () {var count = 0 function counter() { count += 1; return count; } return counter; } var getCounter = fn(); // This step is very important! getCounter();Copy the code

In this error example, because the count variable is defined inside the function and we call counter() every time, it executes the internal code from top to bottom, creating a new local variable count and returning each time, so we get the same result no matter how many times we call the function.

What about closures? I just marked a very important line of code var getCounter = fn(), we called fn() and assigned its return value to the variable getCounter, and we never called the fn() function again, so the fn() function itself was only executed once, The count variable inside the fn() function is initialized only once, and the return value of fn() is a function, so after we receive the return value of fn() with getCounter, the call to getCounter() function is not fn(). It’s the counter() function returned by fn().

At this point, you should have at least a half-understanding of how closures work: local variables defined inside closures are initialized only once, and the same internal variables are accessed each time a closure method is called (PS: Var demo1 = fn(), demo2 = fn(); var demo1 = fn(), demo2 = fn(); The count in demo1 and demo2 is not shared), if you can understand what I said above, then congratulations, victory is in sight!

If you already know why you call the same variable every time you call a closure, you might be wondering why variables inside a closure can be persisted. This involves a bit of knowledge about event loops, variable life cycles, and memory, but I’ll try to explain it as easily as possible.

In fact, the persistence of variables in closures can be explained by memory mechanisms as well as by the call stack, event queue, and other mechanisms in eventLoop, but the mechanism is analyzed from a slightly different perspective. Let’s explain this in terms of the easy-to-understand variable life cycle.

Global variables are destroyed when the window object is destroyed, while local variables are destroyed when their execution environment is destroyed. When a function is declared but not called, no internal runtime environment is created. We call fn() when we receive it with a variable such as var demo = fn(). So now we have a count variable initialized in a particular runtime, and because the demo variable receives a function returned by FN () that can be used to access the count in that particular runtime, we can operate on the same count variable inside the closure every time we call the demo method, The demo variable exists (unless it is overwritten or deleted) until its runtime environment is destroyed. In combination with the above mentioned internal variables in the closure function are executed only once, so we have implemented persistence of the internal variables in the closure.

Extension:

1. Why are variables not shared between multiple instances of the same closure?

fn() { ... Closure code... } var demo1 = fn(), demo2 = fn();Copy the code

Since fn() is called once when demo1 and demo2 are declared, they have different operating environments. The count accessed by demo1 and demo2 is not the same. If you want to ensure that the internal variables of the closure accessed globally are the same, you should only call the closure once.

We already know the principle of closures, but in practice, we usually don’t use the basic closure. Instead, we use some advanced methods, such as: Pass parameters and differentiation return results

Such as:

function fn() { var a = 0, b = 1, c = 2; return function(type) { if(type == 0) { return a; } else if(type == 1) { return b; } else { return c; } } } var result = fn(); result(0); // return 0 result(1); // return 1 result(2); / / return 2Copy the code

Also applicable to our usual use of very much timer and function anti – shake throttling and so on, here is not much to repeat, we can go down to understand.

Conclusion:

1. An instance of a closure initializes the internal variables in the closure only once, since it calls the closure method only once and then calls the functions in the closure return value.

2. Because we receive the function returned by the closure with a variable that has access to local variables in the closure, we can always access a variable in the closure and change its value.

The above is a personal view of closures, some places for beginners to understand so not accurate, and some places may indeed exist in the understanding of the error, I hope you can help correct!