preface

When was the closure created and when was it destroyed? What about the implementation?

At the beginning of learning closures, I swallowed the date πŸ˜”. I hope this time I can calm down and meditate, and have a deeper understanding of closures.

🀭 To better understand closures, it is necessary to understand the scope and execution context:

JavaScript execution context – Execution stack

Javascript dynamic scope you don’t know about

Words don’t say much, come up is a thinking question πŸ€”

		var name = "The Window";
        var object = {
            name: "My Object".getNameFunc: function () {
                return function () {
                    return this.name; }; }}; alert(object.getNameFunc()());Copy the code

πŸ‘† of course, the JS foundation is solid, must understand the inside of the review, look at the content, for this problem will be able to solve the ✊

Click here to see
Obj.getnamefunc ()() actually calls an anonymous function in the global scope; this refers to the window. The function name is separated from the function (or function value). Do not assume that the this inside the function refers to where the function is. The execution environment of anonymous functions is global, so their this object usually points to window

What is a closure

To see how ruby said πŸ‘‡

Closures are functions that have access to variables in the scope of another functionCopy the code

Let’s start with the MDN definition πŸ‘‡

Function and references to its surrounding state (**lexical environment **) are bundled together to form the **closure** (**closure**). That is, closures allow you to access outer function scopes from inner functions. In JavaScript, whenever a function is created, a closure is generated when the function is generated.Copy the code

Closures are functions that can access free variables. Arguments free variables refer to variables that are used in a function, but are neither function arguments nor local variables to the function.

There are a variety of definitions for closures on the Internet. Everyone's understanding of closures is different, so I don't want to define closures, so I can decide πŸ‘ŠCopy the code

If you want to understand, there are two ways to understand:

1️ closure is a nested internal function (most people)

2️ one of the objects (few people) containing the variable (or function) being referenced

I think closures exist with nested internal functions 😊

For the second understanding, let’s write a demoπŸ‘‡

function count () {
            var x = 0
            return {
                add() {
                    x++;
                },
                print() {
                    console.log(x)
                }
            }
        }
        let demo = count();
        demo.add()
        demo.print()
        demo.add()
        demo.print()
Copy the code

Well πŸ™ƒ can only be understood can not be explained, go down to see again!

The life cycle of closures

Closure causes

The first thing to understand is the concept of scope chains, which is actually quite simple. There are only two scopes in ES5

1️ global scope 2️ local scope

When accessing a variable, the interpreter first looks for an identifier in the current scope. If it doesn’t find one, the interpreter looks in the parent scope until the variable’s identifier is found or not in the parent scope. This is the scope chain. Note that each subfunction copies the parent scope, forming a chain of scopes. Such as:

var x = 1;
function demo() {
  var x = 2
  function demo2() {
    var x = 3;
    console.log(x);/ / 3}}Copy the code

In the above code, I personally understand that the scope of demo function refers to the global scope (window) and itself, while the scope of demo2 function refers to the global scope (window), demo and itself. If the global scope is not found, an error ❌ will be reported

The nature of closure generation πŸ’― There are references to parent scopes in the current environment. Take the example above :πŸ‘‡

		var x = 1;
        function demo() {
            var x = 2

            function demo2() {
                console.log(x); 
            }
            return demo2;
        }
        var h = demo();
        h()   / / 2
Copy the code

Here the h variable gets the variable in the parent scope and prints 2. In the current environment, there is a reference to Demo2, which references both the Window Demo and its scope. So Demo2 can access variables in the demo scope.

Question? Do only return functions produce closures? ❓

Getting back to the essence of closures: just make the reference to the parent scope exist so we can do this πŸ‘‡

		var demo2;
        function demo() {
            var x = 2

            demo2 = function () {
                console.log(x); 
            }
            
        }
        demo();
        demo2()    / / 2
Copy the code

Now demo2 has access to the window demo and its scope. So when demo2 searches for variable x, it will search up step by step. When it finds identifier in the nearest demo scope, it will return the result and output 2.

🀭, where the external variable demo2 has a reference to the parent scope, produces a closure that changes form but remains essentially the same.

Closure representation 🀀

Understanding the essence, we start from the real scene, where can reflect the existence of closures ❓

1️ one returns a function, an example has been given above

2️ transfer as a function parameter

var a = 1;
function foo(){
  var a = 2;
  function baz(){
    console.log(a);
  }
  bar(baz);
}
function bar(fn){
  // This is the closure
  fn();
}
// Print 2 instead of 1
foo();
Copy the code

3️ on timers, event listeners, Ajax requests, cross-window communication, Web Workers or any asynchronism, as long as the callbacks are used, they are actually using closures

The following closures hold only the window and the current scope.

/ / timer
setTimeout(function timeHandler(){
  console.log('2222'); },100)

// Event listener
$('#div').click(function(){
  console.log('DIV Click');
})
Copy the code

4️ discount (immediate execution of function expression) create closure that stores the global scope window and the scope of the current function, so global variables can be allowed.

var x = 22;
(function IIFE(){
  / / output 22
  console.log(x); }) ();Copy the code

Condition of generation

1️ retail function nesting

2️ internal function references data of external function (variable/function)

Destruction of closure

When it comes to closure destruction, the first thing to talk about is V8’s garbage collection mechanism

V8 garbage collection, I think I’ll start a new chapter about it at 🀭

Let’s talk about the garbage collection mechanism:

In javascript, if an object is no longer referenced, then the object is garbage collected. If two objects reference each other and are no longer referenced by a third party, then the two referenced objects are also reclaimed

πŸ‘† Simply put, if a reference object is not referenced,V8’s garbage collection mechanism destroys it, and the closure carries the scope of the function that contains it, thus consuming more memory than other functions. Therefore, you can manually de-reference anonymous functions to free up memory.

The disadvantage is to generate multiple private scopes (heap memory) that are not destroyed. In addition to the performance impact, it can be dangerous if the currently saved closure, or its parent scope, has HTML elements 🚫

Pay attention to

Closures cause variables in a function to be stored in memory, which is expensive, so don’t abuse closures because they can cause performance problems for web pages and, in IE, memory leaks. The solution is to remove all unused local variables before exiting the function.

Closures change the values of variables inside the parent function, outside the parent function. So, if you use a parent function as an object, a closure as its Public Method, and internal variables as its private values, be careful not to arbitrarily change the values of the parent function’s internal variables.

Of course, the proper use of closures can also solve a lot of problems, I think the idea of functional programming must be associated with closures.

For example, higher-order functions 🀭 Are currified

conclusion

  • πŸ’― There are references to parent scopes in the current environment
  • Referenced variables are not destroyed until the closure is destroyed
  • Closures generate private scopes and consume a lot of memory, so do not abuse closures. For reference types, stored in heap memory can cause memory leaks, especially if the parent scope of a closure contains HTML elements, which can be dangerous 🚫
  • Closures carry the scope of the function that contains them and therefore take up more memory than other functions. Therefore, you can manually de-reference anonymous functions to free up memory.
  • Closure application scenarios: modularization and Currization

reference

Discover the power of closures in JavaScript

Ruan Yifeng closure

The underlying mechanics of JavaScript closures

Discover the power of closures in JavaScript

Diagram scopes and closures