The introduction

JavaScript closures are a curious feature that we don’t see in any other language we study; Of course, there is no need to myth it too, think this is a what awesome existence; No matter what you encounter, just say “this is just so” in your mind, and learn to learn. Closures themselves are relatively simple, so this article focuses on why closures exist and the details behind them that you might have missed.

First, let’s take a macro view of closures:

A closure refers to a function that refers to a function outside the scope. To be precise, it should be the whole composed of functions that refer to external variables + referenced external variables. The property is that the referenced external variable persists even after the external function is destroyed. Why does it exist and not be destroyed along with the external function? That ‘s a question. So the logical place to start with closures is here: garbage collection

The garbage collection

In order not to complicate things too much, I’m going to talk briefly about the recycle algorithm; You’ve probably heard of tag clearing algorithms (check out the Little Red Book if you haven’t). The tag clearing algorithm basically marks each variable first and then iterates from the global scope (which is the key difference from reference counting and does not generate a loop count), similar to DFS. If a variable can be traversed, it is accessible and unmarked; Variables that remain marked after that are reclaimed. (After the garbage collection program will also collate memory fragments, and v8 garbage collection algorithm is generational garbage collection algorithm, divided into new area and old area, new area is divided into from and to… ; Of course, these are not important to this issue, but you can check out sanyuan’s blog. But the short answer is, because it can be traversed, it’s not cleared. Why is it possible to iterate?

For those of you who are starting to talk nonsense, JavaScript uses a static scope, and a static scope is defined blabla at function definition time. It’s as good as it is not.

Closures are closely related to scope chains. Suppose the inner function B is defined inside the outer function A, which is an inner function. The inner function adds the active object containing the function to its scope chain, and the process looks something like this:

  • The outer functionExecution contextPush, createThe variable object
  • Enter the code execution phase and activate the variable object
  • The inner function now combines the global variable object with the outerActive objectsAdded to the beforehand[[scope]]In the
  • When the inner function is called, the[[scope]]In, the variable object is taken out and added to its scope chain, and then its own active object is pushed into the front of the scope chain, forming the final scope chain

And b is actually a value accessed through the scope chain; The reason is that, in step 3 above, the inner function preadds the variable object of the outer scope.

Here’s the key:

The internal function is returned by the external function, assuming it is received by a variable in the global scope. According to the tag clearing algorithm, DFS can be traced from the global scope to the variable object of the external function, so it will not be cleared. It doesn’t have to be received by a global variable, it just has to be accessible from the global scope, such as being added to a macro task queue waiting to be executed.

Attentive students will notice the above words: variable object, active object, execution context, scope chain, inner function, explained one by one.

  1. Execution Context

    • There are two types of execution context, global execution context (window object) and function execution context; Each context has an associated variable object (the variable object of the global execution context is also the Window object) that stores all variables and functions defined in that execution context.

    • The lifecycle of an execution context is divided into three phases:

      1. Create phase (create variable object, determine this to point to, and other required states)
      2. Code execution phase (when the variable object is activated as an active object and properties in the active object can be accessed)
      3. Destruction phase (reclaim memory space)
    • The creation of variable objects is also divided into several stages:

      1. createargumentsobject
      2. For the functionparameterCreate a properties
      3. Search for all in that execution contextFunction declarationAnd create the properties
      4. Search for all in the execution contextVariable declarationsAnd create the properties
      // For example
      function foo(a) {
        var b = 2;
        function c() {}
        var d = function() {};
      }
      foo(1);
      // Unpack the calling procedure:
      // Create a variable object as follows:
      VO = {
          arguments: {
              0: 1.length: 1
          },
          a: 1.b: undefined.c: reference to function c(){},
          d: undefined
      }
      // Enter the code execution phase and become the active object as follows:
      AO = {
        arguments: {
              0: 1.length: 1
          },
          a: 1.b: 2.c: reference to function c(){},
          d: reference to function (){}}Copy the code
    • Variable objects and active objects are essentially the same thing, but in different life cycles of execution contexts. Variable objects are engine objects and cannot be accessed in the JavaScript environment. When the execution context enters the code execution phase, the variable object associated with it is activated and becomes an active object

  2. The scope chain

    • JavaScript uses lexical scope, that is, static scope

    • A scope is a collection of accessible variables, functions, and objects. Javascript can define global and local scopes

    • A scope chain, as the name implies, is a linked list of scopes, precisely a list of Pointers, each pointing to a variable object. We’ve all referred to global variables, and this is actually the result of accessing the scope chain, so when you refer to a variable, you look up the current active object, and you work your way up to the global variable object, and that’s what the scope chain does. You may ask what is the relationship between scope and active objects? All I can tell you is that JavaScript scoping is a static concept, defined at function definition, which dictates how variables are found. An active object is an entity that is created dynamically when a function is called, and is added to the scope chain of an internal function.

    • Take a look at this example: What is static scope

      var value = 1;
      
      function foo() {
          console.log(value);
      }
      
      function bar() {
          var value = 2;
          foo();
      }
      
      bar();
      Copy the code

      It’s 1. Did you do that right?

      Reason: Foo is not defined in bar. If you get confused, you may have misunderstood closures.

  3. Internal function

    A function nested within another function by definition

reference

Little red book

www.jianshu.com/p/330b1505e…