Some teachers say there are two beasts of JavaScript: prototypes and closures

Some teachers say that there are two difficulties in JavaScript: async and closures

Anyway, both of them have closures, so this is really important.

Today I’m going to talk about closures in detail, and you will certainly have a harvest. If you don’t see it, you’re not watching it. If you don’t understand, you can comment on the private message and I’ll tell you. Anyway, I think the two beasts have conquered, and I am the invincible little girl. . :.゚, (. ◕ ‿ ◕.) ノ ゚. :. + ゚

I watched two teachers’ classes. The first teacher’s lecture was very in-depth, but not clear, so I didn’t understand it at the end. It was not until the second teacher came up to analyze the concept carefully that I suddenly saw the light. Let’s combine them today.

@[toc]

 


concept

What is a closure? To understand what a closure is, start with the concept.

 

Closures are functions that have access to variables in the scope of another function. JavaScript Advanced Programming

(!!!!!! Remember this English word, it will be useful below)

 

A scope can access local variables inside another function.

 

In the figure below, the three scopes are nested together: the global scope has a scope for Fun, the local variable a in Fun, and the function foo, which also has its own scope. Whether the a variable of Fun is called from foo or the a variable of Fun is called from the global scope, a closure is formed.

 


How do you generate closures?

  • A closure occurs when an internal function references a variable (function) of an external function

  • Closures occur when a child function references a variable (function) of a parent function

 

The above two statements are the same, in the case of the conceptual diagram, foo calls a variable or function of Fun.

 

Solving Problem 1

  • A closure occurs when an internal function references a variable (function) of an external function

  • Closures occur when a child function references a variable (function) of a parent function

 

You might say, "I don't understand. How can an internal reference to an external variable generate a closure?"

 

Here are some examples.

For example :chestnut: the closure was generated when the inner function was not called

                     function Fun() {

                            var a = 1

                            function foo(){

                                   console.log(a)

                            }

                     }

                     Fun()

Copy the code

In the above code, looking at the console, I put a breakpoint on Fun(). At this time, you can see that I have circled the scope on the right, and there is only a global below.

Then click Next.

 

If you don’t know why I’m typing here, or what I mentioned below, you need to go back and study, okayVariable promotion, scope, execution contextThe content of the.

That’s when we get to the var a = 1 step. The scope on the right has changed and a local appears. There’s also a foo in local. If you look at the call stack I circled in the red box above, you are already calling Fun. That is, local now refers to the Fun scope.

If you click on ==local=>foo=>[[Scopes]]=>0==, you’ll see the closure. It says a: undefined, which is the English word for the closure I told you to remember. Closure(Fun) means that the Closure of Fun has been formed. With the help of variable promotion, as long as the inner function is parsed, the inner function does not need to be executed.

Why has a closure for Fun been formed?

See below. Since foo has been parsed at this point, meaning it has called a, the closure is formed. But a=1 hasn’t been executed yet, so a is now undefined.

A counter example: Chestnut: Further understanding that the closure is already generated when the inner function is not called

If you write code like this it doesn’t form a closure.

Take a look at the console, and there are no closures

You know why? Once again, go back to schoolVariable promotion, scope, execution context.

Only functions declared by function are promoted. Functions declared by var only promote the function name. That is, the body of the function has not yet been parsed, and foo has not yet called Fun’s a variable. You can go ahead and try it out for yourself. When you enter foo, all you get is the closure (´,,•ω•,, ‘).

For example: Chestnut: An internal function call generates a closure

After looking at the above two examples, you’ve got the idea, of course, that closures are generated when functions are parsed, and closures are generated when functions are called. The only difference is that by the time you call it, a has already been assigned. So now you see a:1.

Chestnut: The inner function executes without calling the variables of the outer function, and no closure is generated

As you can see from the figure below, there is no relation between the variables of the inner function and the outer function. So even if the inner function executes, the scope on the right side does not show the generated closure. (low ‘omega ` low)

Solving Problem 2

  • A closure occurs when an internal function references a variable (function) of an external function

  • Closures occur when a child function references a variable (function) of a parent function

 

You might ask: "You gave the concept of calling variables, now how do you add (function),

Calls to functions in the scope of other functions also form closures?"

 

For example: Chestnut: An inner function calling another subfunction of an outer function produces a closure

If an internal function calls something from an external function, it is a closure, whether it is an ordinary variable or a function.

Solve Problem 3

  • A closure occurs when an internal function references a variable (function) of an external function

  • Closures occur when a child function references a variable (function) of a parent function

 

You might also ask, "Don't you think that calls to Fun from the outer scope also produce closures? I didn't

See how to call outside. What's more, you didn't mention global scope for both internal functions."

 

To clarify, the outer scope does call the internal variables or functions of a function, but only with the help of nested subfunctions within that function.

For example: Chestnut: How does an external scope call an internal variable to produce a closure

                     function Fun() {

                            var a = 1

                            function foo() {

                                   console.log(a)

                            }

                            return foo;

                     }

                     var aa=Fun();

Copy the code

Take a look at the code above and LET me help you.

When the above code is run, the global context is handled first and the variables are promoted. Then the aa=Fun() assignment statement is executed, calling Fun. At this point, Fun is entered, and Fun performs execution context processing in the function. The code should logically look like this:

 

By the time you get into Fun, the closure is already created when the variable is promoted. Because the breakpoint is at a=1. At this point this sentence has not been executed, which means it has not been copied to A, and there is already a closure on the right. And shows a:undefined

If you click on the next sentence, you’ll get to return foo, where a has been assigned, and you’ll see a:1 in the closure on the right

If aa is assigned globally, the closure will be generated in Fun. If aa is assigned globally, the closure will be generated in Fun. If aa is assigned globally, the closure will be generated in Fun.

In summary, the conditions that produce closures

  • Nested function

  • The internal function references the data of the external function (variable/function)


The lifecycle of closures

produce

Generated: generated when the nested inner function definition is finished executing (not calling)

After a few examples above we can see when closures are created.

When an internal function definition is completed, it has several meanings

  • You don’t need to execute an internal function

  • Internal function parsing

 

As you can see from the first, second, and last examples above, the function declared by the function is resolved when the variable is promoted. If a function is declared with var instead of function, then function parsing generates closures when a function is assigned to var. You don’t need to execute an internal function.

death

Death: when a nested inner function becomes a garbage object

What does it mean when an internal function becomes a garbage object

  • When the variable that called the inner function is destroyed.

 

Let’s continue with the last example above. As I mentioned above, execute var aa=Fun(); The closure has been generated by. So now let’s put the break point down at aa().

Executing aa() is equivalent to calling foo. Click Next to see how aa() executes. You’ll see that the closure exists on the right, because you’re calling aa, and aa refers to Fun. That is, closures are present when AA executes. The closure still exists after the first AA, because there’s a second AA, which I didn’t write down, but how do you know that you’re not going to use it again when you actually write the program.

 

So as long as you assign the value, the closure will always exist whether you execute it or not. If you want it to disappear, you destroy the variable that called the inner function, that is, aa=null, and then the closure disappears.


What closures do

  • Allows the outside of the function to manipulate (read and write) the data inside the function (variables/functions)

This is already shown in solving problem 3. If you forget, go up and look.

  • Using variables inside a function that live in memory after the function has finished executing (prolonging the life of local variables)

This has just been explained in the lifecycle death of closures. If you forget, go up and look.

 

The problem

1. After the function is executed, does the local variable declared inside the function still exist?

Generally speaking, it doesn’t exist. But you can keep it alive with closures (see closure lifecycle for an instance)

2. Can local variables inside a function be accessed directly from outside the function?

Generally not, but you can do so through closures that make internal variables visible to the outside.

 

* * *

Common closures

  • Function as the return value of another function

  • Pass the function as an argument to another function call


Application of closures – defines JS modules

What is a JS module

* A js file with a specific function

* Encapsulate all data and functionality in a single (private) function

* An object or function that exposes only one or n methods

* Users of a module only need to call methods from objects exposed by the module to implement the corresponding functions

 

Two kinds of writing

Returns a value using an external function

The following figure shows the two internal functions as return values, which can be used after the external variables are declared.

Use anonymous function calls

Using anonymous functions to expose methods from calls, you can call them directly without declaring variables.


Disadvantages and solutions to closures

# # #

* After the function is executed, the local variables in the function are not freed, and the memory usage becomes longer

* Easy to cause memory leaks

 

For example, in the image below, I created a very large array. Now the closure is generated after an external AA assignment. If I forget to release it, it consumes memory for a long time and leaks memory.

To solve

* Don’t use closures if you can

* Timely release

Var aa= Fun() =null

 

supplement

Memory overflow:

  • An error that occurs when a program is running

  • A memory overflow error is thrown when the program needs more memory than is available.

 

Memory leak:

  • The occupied memory was not freed

– Memory leak accumulation will lead to memory overflow

  • Common memory leaks

– closure

– Unexpected global variables

– Timers or callbacks not cleaned up in time

 


How many examples?

Example 1: What is output?


                     var name = "The Window";

                     var object = {

                            name: "My Object".getNameFunc: function() {

                                   return function() {

                                          return this.name; }; }};console.log(object.getNameFunc()());

Copy the code

Since you’re calling getNameFunc directly, The this pointer to getNameFunc is global and prints The Window

 

Example 2: Output what?


                     var name2 = "The Window";

                     var object2 = {

                            name2: "My Object".getNameFunc: function() {

                                   var that = this;

                                   return function() {

                                          returnthat.name2; }; }};console.log(object2.getNameFunc()());

Copy the code

You’re calling getNameFunc directly, so the this pointer to getNameFunc is global.

But when we define it, we have a var that = this, which is defined as a method of object2, so this refers to object2. That stores the point to this at that time. Even if this is later called globally and the reference to this changes, it does not affect that, so output My Object

 

Example 3: Output what? (Don’t read it. I have a feeling you won’t understand what I’ve explained. It will only add to the confusion. Of course, if you don’t understand, you can leave a message.


                     function fun(n, o) {

                            console.log(o)

                            return {

                                   fun: function(m) {

                                          return fun(m, n)

                                   }

                            }

                     }

                     var a = fun(0)

                     a.fun(1)

                     a.fun(2)

                     a.fun(3)

                     var b = fun(0).fun(1).fun(2).fun(3)

                     var c = fun(0).fun(1)

                     c.fun(2)

                     c.fun(3)

Copy the code

Take a look at a.run (1), where the call stack shows two funs, which is indeed back to function fun(n,x). The fun is called from the innermost return value, so a new closure is created. A.run (1) then passes another 1, and the original closure still exists, which is equivalent to passing fun(1,0) as two arguments. So it outputs 0. After execution, the newly generated closure dies because there is no global variable to store a.run (1). But the closure of fun(0) stored by the variable A still exists. So when you execute a.run (2) a.run (3), the resulting closure passes in new arguments, along with the arguments passed in the original closure. So it’s going to print 0.

The variable b generates four layers of closures and is preserved.

It makes sense to go to the variable C, which stores two layers of closures. The remaining closures generated by C. run (2) and C. run (3) are not saved, so they are executed on a two-tier closure basis.

So all subsequent executions will change 1 to x, only passing in the new value of n at execution time, 2 or 3.


 

Bang (● ‘∀´●) Added How to understand! I’m such a clever little guy.

I’m Girl Ann, the little wit who hasn’t been programmed yet.