温故知新-JavaScriptのCloureを再認識する

8313 ワード

閉塞の温度
定義:Cloureとは何ですか?
MDN:Close uresの定義は以下の通りである.
A
closure is the commbination of a function bundled together(enclosed)with references to its surrounding state(the)
lexical environment).In other words,a closure gives you access to an outer function's scope from an inner function.In JavaScript,closures are are created every time a function is created,at function creation time.
また、専門性からの説明を見てください.
In programming laggage、a
closure、also
lexical closure or
function closure,is a technique for implementing lexically scoped name binding in a langgage with first-class functions.Operations,a closure is a recording stored a function together with and environment.The enviroting manctions.The engment.The envirotions mancting manctions.The enping manciancting mancting mancting mancting
free variable of the function(variables that are used locally、but defined in an enclosing scope)with the value or reference to which the name was bound when the closure wast created.Unike a pleance the funce
captured variables through the closure's copies of their values or references,even when the function is invoked outside their scope.
簡単に言えば、closureは、関数とその関数を宣言するロケーションから構成されている.
いくつかの点に注意が必要です.
  • a closure is a recordクローズドは、関数(通常はその入口アドレス)と、関数を表す環境(シンボルルックアップテーブルに相当)を格納する構造体である.
  • free variable自由変数(関数の外部で定義されていますが、関数内で参照されている変数).クローズドと関数の最大の違いは、クローズドパケットを捕捉すると、その自由変数がキャプチャー時に決定され、キャプチャ時のコンテキストから逸脱しても、通常どおりに動作することができることである.
  • 下記のコードを見てください.
    var a = 1;
    function test() {
      const b = 1;
      function inner1() {
        var c = a + 2;
    
        function inner2() {
          var d = a + b;
    
          return c;
        };
    
        inner2()
      };
    
      inner1();
    }
    test();
    Chromeを使用して、それぞれinner1()inner2()return cの3箇所でブレークポイント調整を行う.
  • Step 1:プログラムがinner1()まで動作します.コンソールでScopeを見ることができます.LocalGlobalの2つの
  • があります.
  • Step 2:プログラムがinner2()に実行されます.Scopeの中にLocalClosure(test)Globalの3つがあります.Closure(test)の中に関数testで定義されている変数b
  • があります.
  • Step 3:プログラムがreturn cに実行され、ScopeLocalClosure(test)Closure(inner1)GlobalClosure(test)testの4つの項目がコンソールで見られます.bには関数Closure(inner1)で定義されている変数inner1があります.
    内部関数が外部関数宣言の変数を使用しない場合、インスタンスのデバッグを変更してみます.
    var a = 1;
    function test() {
      const b = 1;
      function inner1() {
        var c = a + 2;
    
        function inner2() {
          var d = a + c;
    
          return c;
        };
    
        inner2()
      };
    
      inner1();
    }
    test();
    前のステップに従って調整を続けていくと、プログラムがcまで実行されていることが分かります.inner2()にはScopeがありません.表示された結果:内部関数は、外部関数の変数を参照しないと、クローズドされません.
    MDNの中で言及します
    In JavaScript、closures are created evertime a function is created、at function creation time.
    次にClosure(test)概念をレビューすると、関数入口アドレスと関連する環境を含む.これは関数が作成された時と同じです.この角度から見れば、関数は閉じられています.理論的には、上記の例はクローズドが発生するはずですが、実際にclosureでデバッグが発見されていません.ここで最適化が行われていますか?自由変数がない場合は、クローズド処理は行われません.資料を探しましたが、これは確かにコンパイル技術です.chromeといいます.
    ここで、閉包による必要条件をまとめます.
  • 関数には内部関数、すなわち関数ネスト
  • があります.
  • 内部関数には、外部関数のいずれかを参照する変数、すなわち、自由変数
  • が存在する.
  • 内部関数が実行される
  • .
    解析:なぜLambda liftingはメモリに常駐しているのですか?
    まず結論を出すと、クローズドパケットがメモリに常駐する理由は、クローズドされているclosureが解放されていないことにある.
    function test() {
      var a = 0;
    
      return {
        increase: function() { a++; },
        getValue: function() { return a; },
      };
    }
    
    var obj = test();
    
    obj.getValue();
    obj.increase();
    obj.getValue();
    分析して実行するプロセス:
  • は、最初に実行し、グローバルlexical environment
    GlobalExecutionContext = {
      LexicalEnvironment: {
        EnvironmentRecord: {
          Type: "Object",
          test: < func >
        }
        outer: ,
        ThisBinding: 
      },
      VariableEnvironment: {
        EnvironmentRecord: {
          Type: "Object",
          // Identifier bindings go here
          obj: undefined,
        }
        outer: , 
        ThisBinding: 
      }
    }
  • を作成する.
  • lexical environment関数を実行し、test関数のtest
    FunctionExecutionContextOfTest = {
      LexicalEnvironment: {
        EnvironmentRecord: {
          Type: "Object",
        }
        outer: ,
        ThisBinding: 
      },
      VariableEnvironment: {
        EnvironmentRecord: {
          Type: "Object",
          a: 0,
        }
        outer: , 
        ThisBinding: 
      }
    }
  • に入ります.
  • は1つのオブジェクトに戻り、2つの関数が含まれているlexical environment
    FunctionExecutionContextOfIncrease、
    FunctionExecutionContextOfGetValue: {
      LexicalEnvironment: {
        EnvironmentRecord: {
          Type: "Object",
        }
        outer: ,
        ThisBinding: 
      },
      VariableEnvironment: {
        EnvironmentRecord: {
          Type: "Object",
        }
        outer: , 
        ThisBinding: 
      }
    }
  • です.
  • lexical environmentobj関数を呼び出し、getValueの関数のgetValueに入り、規則に従ってlexical environmentによってGetIdentifierReference(lex, name, strict)を解析し、aの関数のincreaseにおいてlexical environmentを解析できないと、aの対応する外部outerに移ってlexical environmentの中で解析
  • を継続する.
  • は、objincrease関数を呼び出し、プロセスは、objgetValue関数を呼び出すのと同様である.
  • 大体の過程はこうです.FuntionInitializeについては、4.Set F.[[Environment]] to Scope.が見られます.[[Environment]]に関する仕様の説明を見てください.
    Type
    Description
    Lexical Evironment
    The Lexical Evironment that the function was closed over.Used as the outer environment when evaluating the code of the function.objgetValue関数を呼び出して、outerの対応する外部lexical environmentに移って解析を続けます.ここでのlexical environmentは、関数の内部属性[[Scopes]]を指すべきです.
    前のchromeでデバッグした例では、ScopeClosure(test)が現れ、中にはtest関数enviroment recordにおいて他のlexical environmentによって参照されている部分が残っていることがわかる.
    また、obj.getValue()Global lexical environmentで呼び出され、実行されるとき、outerGlobal lexical environmentではない.これは外部語環境参照が論理的に内部語法環境を囲む用語環境を指すからである.
    The outer reference of a(inner)Lexical Evironment is a reference to the Lexical Evironment that logcal surrounds the inner Lexical Evironment.
    締め括りをつけるclosure、関連資料を探して改めて認識し、規範を読んで、専門的な定義を理解する.もとは多くのものは表面の上でそんなに簡単ではありません!
    参考資料
  • 万次元百科Cloure)
  • MDN Cloures
  • ECMAScript® 2019 Language Specification
  • クローズドを解読して、今度はECMAScriptの語法環境から、文脈を実行して言います。
  • すべての書簡式は全部クローズドです。JSの役割領域とCloseureを話します。