Mandatory inclusion means that the returned function has its own independently accessible external scope.

Scope & execution context

Js – scope chain JS – execution context


Introduction to simple Examples

function wrapperFunction() {
  let name = 1;
  
  return function () {
    console.log(name); }}let fuc = wrapperFunction()

fuc()
Copy the code

Here the scope of the FUC forms a simple required environment.



The biggest feature here is that func currently has exclusive access to the wrapperFunction variable environment. You might say that wrapperFunction has access to itself, but when wrapperFunction is executed it is a different environment. The func environment contains the wrapperFunction variables stored in memory.







When will the must-bag go away

The life cycle of the variable depends on the life cycle of the closure. Variables in the outer scope referenced by the closure will survive until the closure function is destroyed. If a variable is referenced by multiple closures, it will not be destroyed until all closures have been garbage collected.

Therefore, we will take the initiative to delete the use of mandatory packages when they are no longer used.

Juejin. Cn/post / 684490…

Timer

(function autorun(){

   let x = 1;

   setTimeout(function log(){

     console.log(x);

   }, 10000);

}) ();

The copy code variable X will survive until the timer callback is executed or clearTimeout() is called. If setInterval() is used here, the variable x will survive until clearInterval() is called. The variable x survives until setTimeout() or setInterval() is called.

Event

(function autorun(){

   let x = 1;

   $(“#btn”).on(“click”, function log(){

     console.log(x);

   });

}) ();

Copy code When the variable x is used in an event handler, it survives until the event handler is removed.

Ajax

(function autorun(){

   let x = 1;

   fetch(“http://”).then(function log(){

     console.log(x);

   });

}) ();

The copy code variable X will survive until the return result from the back end is received and the callback is executed. In the last few examples, we have seen that the log() function lives on after the parent completes execution, and that the log() function is a closure.

In addition to more common asynchronous tasks such as timers, event processing, and Ajax requests, there are other asynchronous apis such as HTML5 Geolocation, WebSockets, requestAnimationFrame() will also use this closure feature. The life cycle of the variable depends on the life cycle of the closure. Variables in the outer scope referenced by the closure will survive until the closure function is destroyed. If a variable is referenced by multiple closures, it will not be destroyed until all closures have been garbage collected.


Classic Interview questions

Write the code: expect the return output to be 5,0,1,2,3,4 every second

Will the package

for (var i = 0; i < 5; i++) {
    setTimeout(function() {
        console.log(i);
    }, 1000);
}

console.log(i); // 5, 5, 5, 5, 5, 5
Copy the code

The execution mechanism of a timer is that it pushes the current function into the event queue until the main process is finished. So let’s look at the results here. When setTimeout is executed, the first callback is pushed into the event queue, which is the same result as the other setTimeouts. And then because they all have the same external scope. Both have access to the I variable. Because the value of I has no block scope. Over the course of the loop, this variable has accumulated to 5.

Execute expression immediately

for (var i = 0; i < 5; i++) {
  (function(j) {
    setTimeout(function() {
      console.log(j);
    }, 1000);
  })(i);
}

console.log(i);
Copy the code

The reason for this is that function expressions are executed immediately through IIFE. Create a unique parent scope for each setTimeout by performing the + argument copy pattern.

SetTimeout API operations

for (var i = 0; i < 5; i++) {
    setTimeout(function(j) {
        console.log(j);
    }, 1000, i);
}

console.log(i);
Copy the code

This is the way arguments are copied as variable objects of the function itself.

let

Block-level scoping

var j = 0
for (let i = 0; i < 5; i++, j++) {
    setTimeout(function() {
        console.log(i);
    }, 1000);
}

console.log(j);
Copy the code


promise

Expect output every second: 0-1-2-3-4-5

const tasks = [];
for (var i = 0; i < 5; i++) {
    ((j) = > {
        tasks.push(new Promise((resolve) = > {
            setTimeout(() = > {
                console.log(j);
                resolve();
            }, 1000 * j);
        }));
    })(i);
}

Promise.all(tasks).then(() = > {
    setTimeout(() = > {
        console.log(i);
    }, 1000);
});

/ / let
const tasks = [];
for (let i = 0; i < 5; i++) {
	tasks.push(new Promise((resolve) = > {
    setTimeout(() = > {
      console.log(i);
      resolve(i);
    }, 1000 * i);
  }));
}

Promise.all(tasks).then((res) = > {
    setTimeout(() = > {
        console.log(res[res.length - 1] + 1);
    }, 1000);
});


Copy the code




Applications at work

A block of code with internal state or internal processing.

  • Hoc higher order function
  • redux
  • router




Memory leaks caused by closures

<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
    </style>
  </head>
  <body>
    <div class="left">LEFT</div>
    <div class="right">RIGHT</div>

    <script type="text/javascript">
      var t = null;

      var replaceThing = function () {
        var o = t;
        var unused = function () {
          if (o) {
            console.log("hi");
          }
        }

        t = {
          longStr: new Array(100000).fill(The '*'),
          someMethod: function () {
            console.log(1)}}}setInterval(replaceThing, 1000)
    </script>

  </body>
</html>
Copy the code



Here, every time the timer method is executed, there will be a reference to the two methods executed before and after. The result is that the data created with each method execution is still accessible.



Closures themselves do not cause a memory leak, but they do cause a leak because the code is not written properly, so that the unreachable scope in the closure is still reachable and cannot be collected by JS garbage collection.




Summary closure definition:

The Little Red Book definition: Anonymous functions are often mistaken for closures. Closures are functions that refer to variables in the scope of another function. Anonymous functions, usually implemented in nested functions, are often mistaken for closures. Closures are functions that refer to variables in the scope of another function, usually implemented in nested functions. MDN defines closures as functions that have access to free variables. So what is a free variable? A free variable is a variable that is used in a function but is neither a function parameter nor a local variable of the function. Closures are made up of two parts: closures = functions + free variables that functions can access. Why, this is not the same as the closure we usually see. ? Don’t worry, this is a theoretical closure. There is also a practical closure. Let’s look at the definition in Uncle Tom’s translated article on closures:

In ECMAScript, closures refer to: theoretically: all functions. Because they both store the data of the upper context at the time of creation. This is true even for simple global variables, since accessing a global variable in a function is equivalent to accessing a free variable, using the outermost scope.

As a practical matter, a closure is a function that exists (for example, if an inner function returns from a parent function) and references free variables in the code even if the context in which it was created has been destroyed