The function of closures

Closures: Internal functions are saved externally

When an internal function is saved externally, a closure is generated. Closures cause the original scope chain not to be released, causing a memory leak (memory footprint)

A) The role of closures

  1. Implement public variables: eg: function accumulator
  2. Can do cache (storage structure) : eg: Eater
  3. You can implement encapsulation and privatize attributes: eg:new Person();
  4. Modular development to prevent contamination of global variables

Examples of closures

1. Accumulator:

Define a timer to count the number of clicks on a web page.

var count = 0;
function addCount() {
    count++;
}
document.body.addEventListener("click", addCount);
Copy the code

Count is a global variable that can be manipulated anywhere else, and if count is reassigned or redefined anywhere else, the timer is broken. At this point, closures come into play.

function addCount() {
    var count = 0;
    var addCount = function() {
        count++;
   }
    return addCount;
}
document.body.addEventListener("click", addCount); Click once -> Output 1 Click twice -> Output 2Copy the code

2. Cache:

function  eater(){
    var food="apple";
    var obj={
        eat:function() {if(food! =""){
                console.log("i am eating "+ food);
                food="";
            }else{
                console.log("eat emtpy ");
            }
        }
        push:function(myFood){ food = myFood; }}returnobj; } var eat1= eater(); eat1.eat(); -> output apple eat1.eat(); -> Print empty eat1.push('banana'); eat1.eat(); Banana - > outputCopy the code

Look at another example of caching:

function isFirstLoad(){
            var list=[];
            return function(option){
                if(list.indexof (option)>=0){// Check if console.log(list.indexof (option)>=0){// Check if console.log(list.indexof (option)>=0){// Check if console.log(list.indexof (option)>=0)'pre-existing')}else{
                    list.push(option);
                    console.log('First incoming'); // Return if notrue}}} var ifl=isFirstLoad(); ifl("zhangsan"); 
ifl("lisi");
ifl("zhangsan");
Copy the code

Print the following on the browser console:

As you can see, if the outside world wants to access the list variable, it can only access it through my function isFirstLoad, which is the only interface I provide to the outside world that wants to access the list. As for how to manipulate _list, I’ve defined it, so all the outside world can do is use my function and pass in a few different arguments.

Finally, by the way, the scope chain is defined at the time it is defined, and it has nothing to do with who executes it and when.

3. Privatization variable: Enter deng for the example below. PrepareWife is the privatization variable formed by Undefind

functionDeng(name,wife){// The var object for Deng(name,wife){// The var object for Deng(name,wife){// The var object for Deng(name,wife){// The var object for Deng(name,wife){// The var object for Deng(name,wife){// The var object for Deng(name,wife){// The var object for Deng(name,wife); var prepareWife="xiaozhang";
    this.name=name;
    this.wife=wife;
    this.divorce=function(){
        this.wife=prepareWife;
    }
    this.changePrepareWife=function(target){
        prepareWife=target;
    }
    this.sayPraprewife=function(){
        console.log(prepareWife);
    }
}
var deng=new Deng('deng'.'xiaoliu');
Copy the code

Examples of simulating private properties of an implementation class:

function Boy(name){
     this.name = name;
     var sex = 'boy';
     this.saySex = function(){
     console.log("my sex is "+sex)
};
}
var xiaoming = new Boy('xiaoming');
console.log(xiaoming.name);
console.log(xiaoming.sex);
xiaoming.saySex();

VM344:16 xiaoming
VM344:18 undefined
VM344:9 my sex is boy
Copy the code

4. Execute functions immediately to resolve closure scope issues:

Definition of a function for an initialization function: such functions are not alive and are released after being executed together. Good for initialization.

function test(){
    var arr=[];
    for(var i=0; i<10; i++){ (function (j){
            arr[j]=function(){
            document.write(j+""); // input 0,1,2,3,4,5,6,7,8,9}}(I); // Pass I to j as an argument. J does not change with I.}return arr;
}
var myArr=test(a);for(var j=0; j<10; j++){ myArr[j](); }Copy the code
<ul>
  <li id="myli">a</li>
  <li id="myli">a</li>
  <li id="myli">a</li>
</ul>
<script type="text/javascript">
function test(){
  var liList=document.getElementsByTagName("li");
  for (i  = 0; i < liList.length; i++) {
    (function(j){
      liList[j].onclick=function(){ console.log(j); }}(I))}}test(a);Copy the code

Let’s start with a piece of code

<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
</ul>
Copy the code
var lis = document.getElementsByTagName("li");
for (var i = 0; i < lis.length; i++) {
    lis[i].onclick = function() { console.log(i); }}Copy the code

After running this code, you might wonder why clicking on any of the Li tags will result in a 3 on the console. After the code runs, a click function is defined for each li tag, but this function is not executed immediately. The click function is executed only when LI is clicked. When click the li executive function, function of the variable I is not defined in the function, according to the js scope chain principle, will continue to contact the upper scope, thus found the I, in the global scope for loop execution has stopped at this moment, at that moment, I have become in the global scope the 3, so the printed 3 of course. To do this, the printed value is the order in which li was clicked, and the closure comes into play again

var lis = document.getElementsByTagName("li");
for (var i = 0; i < lis.length; i++) {
    lis[i].onclick = (function(i) {
       var clickLi = function() { 
           console.log(i);         
       }
       return clickLi;
    })(i)
}
Copy the code

When the for loop executes, the current value of I is immediately passed into clickLi as a parameter, which by default is a local variable inside the function and cannot be manipulated outside the function. So, when you click on Li and execute the clickLi function, you print out the sequential values of Li.

Disadvantages and solutions of closures

Disadvantages: After the function is executed, local variables in the function are not released, occupying the memory for a long time and causing memory leaks.

Solution: can not use closure is not needed, timely release. Such as:

f = null; // make internal functions garbage objects --> recycle closuresCopy the code

In a word, you need it, is the advantage; You don’t need it, it’s a weakness.

Closure considerations

1. Memory leakage The memory overflows

Memory leak: Occupied memory is not released in time. If memory leaks accumulate too much, they tend to overflow.

Common memory leaks:

  1. Unexpected global variables
  2. No timer or callback function to clean up in time
  3. closure

Case 1 example: unexpected global variables

    function fn() {
        a = new Array(10000000);
        console.log(a);
    }
    fn();
Copy the code

Case 2 example: timer or callback function not cleaned up in time

    var intervalId = setInterval(function() {// Console.log is not cleaned after the loop timer is started.The '-') }, 1000) // clearInterval(intervalId); // Clean up timerCopy the code

Case 3: The closure takes up memory

<script type="text/javascript">
  function fn1() { var arr = new Array[100000]; // This array takes up a lot of memoryfunction fn2() {
      console.log(arr.length)
    }
    returnFn2} var f = fn1() f() f = nullCopy the code
2. About the this object in the closure

What this object refers to depends on the environment in which the function is running. If the function is called globally, this in the function refers to the Window object. This is window if the operating environment is Window. Because closures are not methods of that object.

var color="red";
function fn() {return this.color;
}
var obj={
    color:"yellow",
    fn:function() {return function(){// returns an anonymous functionreturnthis.color; } } } console.log(fn()); Var b=obj.fn(); //b is the variable under window, and the value obtained is console.log(b()), the anonymous function returned by the fn method under obj; Log (b.call(obj)); log(b.call(obj)); log(b.call(obj)); //yellow console.log(b.apply(obj)); //yellow console.log(fn.call(obj)); //yellowCopy the code

A variable is used to retrieve the this reference from the previous scope

var color="red";
function fn() {return this.color;
}
var obj={
    color:"yellow",
    fn:function(){ var _this=this; // Assign this to the variable _thisreturn function() {return_this.color; }}} console.log(fn()); //red var b=obj.fn(); console.log(b()); //yellowCopy the code

Private variables can be accessed by passing arguments to the constructor

function Desk(){
    var str=""; // Local variable STR, default value is""
    this.getStr=function() {return str;
    }
    this.setStr=function(value){ str=value; }; } var desk=new Desk(); // Writes values to local variables of the constructor. desk.setStr("zhangPeiYue"); // Get the constructor's local variable console.log(desk.getstr ()); //zhangPeiYueCopy the code