Description and Function of Closure in JavaScript

  • 2021-07-01 06:20:47
  • OfStack

1. What is a closure

Closures are functions that have access to variables in the scope of another function.
Simply put, Javascript allows the use of internal functions--that is, function definitions and function expressions are in the body of another function. Moreover, these inner functions have access to all local variables, parameters, and other inner functions declared in the outer function in which they are located. When one of these inner functions is called outside the outer function that contains them, a closure is formed.

2. Scope of variables

To understand closures, we must first understand the scope of variables.
The scope of variables is nothing more than two kinds: global variables and local variables.

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

Among them, the variables of external functions can be accessed in internal functions because the scope chain of internal functions contains the scope of external functions;

It can also be understood as: the scope of action of internal functions radiates to the scope of action of external functions;


var n=999;
function f1(){
   alert(n);
}
f1(); // 999

On the other hand, it is naturally impossible to read local variables inside a function outside the function.


function f1(){
   var n=999;
}
alert(n); // error

There is one place to note that when declaring variables inside a function, 1 must use the var command. If you don't use it, you actually declare 1 global variable!


function f1(){
    n=999;
}
f1();
alert(n); // 999

3. Several writing and usage of closures

3.1 Add 1 attribute to the function


function Circle(r) { 
this.r = r; 
} 
Circle.PI = 3.14159; 
Circle.prototype.area = function() { 
return Circle.PI * this.r * this.r; 
} 
var c = new Circle(1.0); 
alert(c.area()); //3.14159

3.2 is to declare a variable and assign a function to the variable as a value


var Circle = function() { 
var obj = new Object(); 
obj.PI = 3.14159; 

obj.area = function( r ) { 
return this.PI * r * r; 
} 
return obj; 
} 
var c = new Circle(); 
alert( c.area( 1.0 ) ); //3.14159

3.3. This method is widely used and most convenient. var obj = {} is to declare an empty object


var Circle={ 
"PI":3.14159, 
"area":function(r){ 
return this.PI * r * r; 
} 
}; 
alert( Circle.area(1.0) );//3.14159

4. The main function of closure

Closures can be used in many places. Its greatest use is twofold: one is to read the variables inside the function mentioned earlier, and the other is to keep the values of these variables in memory at all times.

4.1. How to read local variables from outside?

For various reasons, we sometimes need to get local variables in functions. But, as I said earlier, under normal circumstances, this cannot be done, and it can only be achieved through workarounds.

That is to define another function inside the function.


function f1(){
    var n=999;
    function f2(){
        alert(n); // 999
    }
}

In the above code, the function f2 is included inside the function f1, and all the local variables inside f1 are visible to f2. But the other way around, the local variables inside f2 are invisible to f1. This is the unique "chain scope" structure of Javascript language (chain scope), and the child object will look 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 it is not true.

Since f2 can read local variables in f1, we can read its internal variables outside f1 by taking f2 as the return value!


function f1(){
    var n=999;
    function f2(){
          alert(n); 
    }
    return f2;
}
var result=f1();
result(); // 999

4.2. How to keep the value of a variable in memory all the time?


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 a closure f2 function. It runs twice, the first time with a value of 999 and the second time with a value of 1000. This proves that the local variable n1 in the function f1 is kept in memory and is not automatically cleared after the f1 call.

Why is this happening? The reason is that f1 is the parent function of f2, and f2 is assigned a global variable, which leads to f2 always in memory, while the existence of f2 depends on f1, so f1 is always in memory and will not be collected by garbage collection mechanism (garbage collection) after the call.

Another notable point in this code is the line "nAdd=function () {n+=1}". First of all, the var keyword is not used before nAdd, so nAdd is a global variable, not a local variable. Secondly, the value of nAdd is an anonymous function (anonymous function), and this anonymous function itself is a closure, so nAdd is equivalent to an setter, which can operate on local variables inside the function outside the function.

5. Closures and this Objects

Using this objects in closures may cause 1 problem. Because the execution of an anonymous function is global, its this object usually points to window. The code is as follows:


var name = "The window";
var object = {
name:"My object",
getNameFun:function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFun(){}); //"The window" (In non-strict mode) 

Save the this object in the external scope in a variable that the closure can access, and you can let the closure access the object. The code is as follows:


function f1(){
   var n=999;
}
alert(n); // error
0

6. Closures and Memory Leaks

Specifically, if an HTML element is held in the scope of the closure, it means that the element cannot be destroyed. As follows:


function f1(){
   var n=999;
}
alert(n); // error
1

The above code creates a closure that acts as an element element event handler, which in turn creates a circular reference. Because the anonymous function holds a reference to the active object of assignHandler (), the number of references to element cannot be reduced. As long as the anonymous function exists, the reference number of element is at least 1, so the memory occupied by it will not be reclaimed.

Solve the internal non-recycling problem by rewriting the code:


function f1(){
   var n=999;
}
alert(n); // error
2

In the above code, the implementation closure does not directly refer to element, and the active object containing the function will still save 1 reference. Therefore, it is necessary to set the variable of element to null, so that its occupied memory can be recovered normally.

7. Notices for using closures

1) Because closures will make the variables in the function are stored in memory, memory consumption is very large, so we can not abuse closures, otherwise it will cause performance problems of web pages, which may lead to memory leakage in IE. The solution is to delete all local variables that are not used before exiting the function.

2) Closures change the values of variables inside the parent function outside the parent function. So, if you use the parent function as an object (object), the closure as its common method (Public Method), and the internal variables as its private properties (private value), be careful not to change the values of the internal variables of the parent function casually.


Related articles: