JavaScript deep understanding of JS closure

Time:2019-12-11

I. scope of variables

To understand closures, you must first understand JavaScript’s special variable scope.

The scope of a variable is nothing more than two kinds: global variable and local variable.

The special feature of JavaScript is that global variables can be read directly inside functions.

Js code

  var n=999;

  function f1(){
    alert(n);
  }

  f1(); // 999

On the other hand, the local variables in the function cannot be read outside the function.

Js code

  function f1(){
    var n=999;
  }

  alert(n); // error

Here is a place to note that when declaring variables within a function, you must use the VaR command. If not, you actually declare a global variable!

Js code

  function f1(){
    n=999;
  }

  f1();

  alert(n); // 999

——————————————————————————————————–

2. How to read local variables from the outside?

For various reasons, we sometimes need to get local variables in a function. However, as has been said before, under normal circumstances, this can’t be done. It can only be achieved through flexible methods.

That is to define another function inside the function.

Js code

  function f1(){

    n=999;

    function f2(){
      alert(n); // 999
    }

  }

In the above code, function F2 is included in function F1. At this time, all local variables in F1 are visible to F2. But not vice versa. The local variables inside F2 are invisible to F1. This is the unique chain scope structure of JavaScript language,

The child object looks up all the variables of the parent object level by level. Therefore, all variables of the parent object are visible to the child object, otherwise, they do not work.

Since F2 can read the local variables in F1, as long as F2 is taken as the return value, we can not read its internal variables outside F1!

Js code

  function f1(){

    n=999;

    function f2(){
      alert(n);
    }

    return f2;

  }

  var result=f1();

  result(); // 999

——————————————————————————————————–

The concept of closure

The F2 function in the previous code is the closure.

The definition of “closure” in various professional literatures is very abstract and difficult to understand. My understanding is that a closure is a function that can read internal variables of other functions.

In JavaScript language, only the sub function inside the function can read the local variable, so the closure can be simply understood as “a function defined inside a function”.

So, in essence, closure is a bridge that connects the inside and outside of a function.

——————————————————————————————————–b

IV. purpose of closure

Closures can be used in many places. There are two main uses of it. One is to read the variables inside the function mentioned earlier, and the other is to keep the values of these variables in memory.

How to understand this sentence? Look at the code below.

Js code

  function f1(){

    var n=999;

    nAdd=function(){n+=1}

    function f2(){
      alert(n);
    }

    return f2;

  }

  var result=f1();

  result(); // 999

  nAdd();

  result(); // 1000

In this code, result is actually the closure F2 function. It ran two times, the first with 999 and the second with 1000. This proves that the local variable n in function F1 is always kept in memory and is not automatically cleared after F1 is called.

Why is that? The reason is that F1 is the parent function of F2, and F2 is assigned to a global variable, which causes F2 to always be in memory, while the existence of F2 depends on F1, so F1 is always in memory, and will not be recycled by the garbage collection mechanism after the end of the call.

Another noteworthy thing in this code is the line “nAdd = function() {n + = 1}”. First, the VaR keyword is not used before nAdd, so nAdd is a global variable, not a local variable. Second, the value of nAdd is an anonymous function, and this

Anonymous function itself is also a closure, so nAdd is a setter, which can operate the local variables inside the function.

——————————————————————————————————– 

V. precautions for using closures

1) because closures will make variables in functions stored in memory, which consumes a lot of memory, closures cannot be abused, otherwise it will cause performance problems of web pages and memory leakage in ie. The solution is to delete all unused local variables before exiting the function.

2) the closure will change the value of the internal variable of the parent function outside the parent function. Therefore, if you use the parent function as an object, the closure as its public method, and the internal variable as its private value, you should be careful not to use it casually

Change the value of the internal variable of the parent function.

——————————————————————————————————–

Vi. thinking questions

If you can understand the running results of the following code, you should understand the running mechanism of closures.

Js code
  var name = “The Window”;   
  var object = {  
    name : “My Object”,  
    getNameFunc : function(){  
      return function(){  
        return this.name;  
     };   
    }   
};  
alert(object.getNameFunc()());  //The Window

——————————————————————————————————–
JavaScript closure example

function outerFun()
 {
  var a=0;
  function innerFun()
  {
   a++;
   alert(a);
  }    
 }
innerFun()

The above code is wrong. The scope of innerfun() is inside outerfun(). It is wrong to call it outside outerfun()

Change to the following, that is, closure:

Js code

function outerFun()
{
 var a=0;
 function innerFun()
 {
  a++;
  alert(a);
 }
Return innerfun; / / note here
}
var obj=outerFun();
Obj(); / / result is 1
Obj(); / / result is 2
var obj2=outerFun();
Obj2(); / / result is 1
Obj2(); / / result is 2

What is a closure:

When an internal function is referenced outside its scope, a closure of the internal function is created. If the internal function references variables located in the external function, these variables will not be released in memory after the external function is called, because the closure needs them

——————————————————————————————————–

Let’s take another example

Js code

function outerFun()
{
 var a =0;
 alert(a);  
}
var a=4;
outerFun();
alert(a);

The result is 0,4.. because the VaR keyword is used inside the function to maintain the scope of a within outfun()

Look at the following code:

Js code

function outerFun()
{
/ / no var
 a =0;
 alert(a);  
}
var a=4;
outerFun();
alert(a);
It’s strange that the result is 0,0. Why?

Scope chain is a term describing a path along which the value of a variable can be determined. When a = 0 is executed, since the VaR keyword is not used, the assignment operation will follow the scope chain to var a = 4; and change its value

————————————————————————————————————————————————–

If you don’t understand JavaScript closures very well, please see the following reprinted article: (reprinted: http://www.felixwoo.com/archives/247)

What is closure?

The official “explanation is that a closure is an expression (usually a function) that has many variables and an environment that binds them, so these variables are also part of the expression.
It is believed that few people can understand this sentence directly, because what he describes is too academic. In fact, the popular saying is:All functions in JavaScript are a closure。 However, in general, the closures generated by nested functions are more powerful, which are also what we call “closures” most of the time. Look at the following code:

function a() {  var i = 0;  function b() { alert(++i); }  return b;}var c = a();c();

This code has two characteristics:

1. Function B is nested in function a;

2. Function a returns function B.

The reference relationship is as follows:

In this way, after executing var C = a(), the variable C actually points to function B, and then after executing c(), a window will pop up to display the value of I (1 for the first time). This code actually creates a closure. Why? Because variable C outside function a refers to function B inside function a, that is to say:

  When the inner function B of function a is referenced by a variable other than function a, a closure is created.

Let’s talk more thoroughly. The so-called “closure” is to define another function in the constructor body as the method function of the target object, and the method function of this object in turn refers to the temporary variable in the outer function body. This makes it possible to indirectly maintain the temporary variable values used by the original constructor body as long as the target object can maintain its methods throughout its lifetime. Although the initial constructor call has ended and the names of temporary variables have disappeared, the value of the variable can always be referenced in the method of the target object, and the value can only be accessed through this method. Even if the same constructor is called again, only new objects and methods will be generated. The new temporary variable only corresponds to the new value, which is independent of the last call.

What is the function of closure?

In short, the function of closures is that after a is executed and returned, closures make the garbage collection mechanism GC of JavaScript not reclaim the resources occupied by a, because the execution of the internal function B of a depends on the variables in a. This is a very straightforward description of the role of closures. It is neither professional nor rigorous, but it probably means that understanding closures requires a gradual process.

In the above example, I in a always exists after function a returns due to the existence of closures, so that every time c() is executed, I is the value of I from alert after adding 1.

So let’s imagine another situation. If a doesn’t return function B, it’s completely different. Since B is not returned to the outside world of a, but is referenced by a, and a will only be referenced by B at this time, so functions a and B refer to each other without being disturbed by the outside world (referenced by the outside world), and functions a and B will be recycled by GC. (the garbage collection mechanism of JavaScript will be described in detail later)

The micro world in closures

If we want to know more about closures and the relationship between function a and nested function B, we need to introduce other concepts: the execution context, the call object, the scope and the scope chain of functions. This paper takes the process of function a from definition to execution as an example to illustrate these concepts.

  1. WhenDefinitionWhen function a is used, the JS interpreter willScope chainSet toThe “environment” in which a is defined, if a is a global function, there are only window objects in the scope chain.
  2. WhenimplementWhen function a is used, a will enter the correspondingExecution context
  3. In the process of creating the execution environment, a scope attribute will be added to a, that is, a’sScope of action, which is the scope chain in step 1. That is, the scope chain of a.scope = a.
  4. Then the execution environment creates aCall object。 An active object is also an object with properties, but it does not have a prototype and cannot be accessed directly through JavaScript code. After creating the active object, add the active object to the top of the scope chain of A. At this point, the scope chain of a includes two objects: the active object of a and the window object.
  5. The next step is to add an arguments property on the active object that holds the arguments passed when function a is called.
  6. Finally, all the parameters of function a and the references of internal function B are added to the active object of A. In this step, the definition of function B is completed, so as in step 3, the scope chain of function B is set to the environment defined by B, that is, the scope of A.

This completes the steps from definition to execution of function a. At this time, a returns the reference of function B to C, and the scope chain of function B contains the reference to the active object of function a, that is, B can access all variables and functions defined in a. Function B is referenced by C, and function B depends on function a, so function a will not be recycled by GC after returning.

When function B is executed, it will follow the above steps. Therefore, the scope chain of B includes three objects: the active object of B, the active object of a and the window object, as shown in the following figure:

As shown in the figure, when accessing a variable in function B, the search order is:

  1. Search the active object of itself first, return if it exists, and continue to search the active object of function a if it does not exist, and then search until it is found.
  2. If there is a prototype object in function B, after finding its own active object, first find its own prototype object, and then continue to find. This is the variable lookup mechanism in JavaScript.
  3. If the entire scope chain cannot be found, undefined is returned.

In summary, two important words are mentioned in this paragraph: functionalDefinitionAndimplement。 The scope of a function is defined when the function is defined, not when it is executed (see steps 1 and 3). Use a piece of code to illustrate the problem:

function f(x) {   var g = function () { return x; }  return g;}var h = f(1);alert(h());

In this code, the variable H points to the anonymous function in F (returned by G).

  • Suppose the scope of function H is determined by executing alert (h()), then the scope chain of H is: H’s active object – > alert’s active object – > window object.
  • Suppose that the scope of function H is determined at the time of definition, that is to say, the anonymous function pointed to by H has been determined at the time of definition. When executing, the scope chain of H is: H’s active object – > F’s active object – > window object.

If the first assumption is true, the output value is undefined; if the second assumption is true, the output value is 1.

The running results show that the second assumption is correct, indicating that the scope of the function is indeed determined when the function is defined.

IV. application scenarios of closures
Protect variables within functions. In the first example, I in function a can only be accessed by function B, but can’t be accessed by other ways, so I’s security is protected.

  1. Maintain a variable in memory. As in the previous example, because of the closure, I in function a always exists in memory, so every time c() is executed, I will be added by 1.
  2. Implement JS private properties and private methods by protecting the security of variables (cannot be accessed externally)
    Private properties and methods cannot be accessed outside of the constructor

    function Constructor(…) {  
      var that = this;  
      var membername = value; 
      function membername(…) {…}
    }

The above three points are the most basic application scenarios of closures, from which many classic cases are derived.

V. garbage collection mechanism of JavaScript

In JavaScript, if an object is no longer referenced, it is recycled by the GC. If two objects refer to each other and are no longer referenced by a third party, the two objects that refer to each other will also be recycled. Because function a is referenced by B, and B is referenced by C outside a, that’s why function a will not be recycled after execution.