実行コンテキスト、モジュール/JavaScript


実行コンテキスト


実行コンテキストの概念

  • C言語では、関数を呼び出すたびに、その関数の呼び出し情報が既存の関数の呼び出し情報の上にスタック状に積み重ねられます.->Call Stack/したがって、開発者は、呼び出しスタック内の呼び出し情報などを使用して、コードの実行プロセスを追跡し、デバッグなどのタスクを実行します.
  • 実行コンテキストは、コールスタックに入る実行情報と同様である.
  • 実行可能コードの抽象概念の記述と区別->実行可能JavaScriptコードブロック(関数)を実行する環境
  • で現在実行されているコンテキストでこのコンテキストに関係のない実行コードが実行されると、新しいコンテキストが作成されスタックに入り、制御権がコンテキストに移動します.
  • グローバルコードeval()関数で実行されるコードを使用し、関数でコードを実行すると実行コンテキストが形成されます.
  • <script>
    console.log("This is global context");
    
    function ExContext1() {
        console.log("This is ExContext1");
    };
    
    function ExContext2() {
        ExContext1();
        console.log("This is ExContext2");
    };
    
    ExContext2();
    </script>
    
    -- 실행 컨텍스트 스택이 전역 컨텍스트 -> ExContext2 -> ExContext1 순으로 쌓이게 된다.

    コンテキスト作成プロセスの実行


    アクティブオブジェクトの作成

  • 実行コンテキストが生成されると、JavaScriptエンジンは、そのコンテキストで実行するために必要な様々な情報を含むオブジェクトをアクティブオブジェクトと呼ぶ.
  • アクティブオブジェクトに使用されるパラメータまたはユーザー定義の変数とオブジェクトを格納し、新しく作成されたコンテキストにアクセスします.(ユーザアクセスX、エンジン内部アクセスO)
  • パラメータオブジェクトの作成

  • の次のステップでパラメータオブジェクトを作成します.以前に作成したアクティブなオブジェクトはarguments propertyとしてargumentsオブジェクトを参照します.
  • スキャン情報の作成

  • の次のステップでは、現在のコンテキストの有効範囲を示すscope情報が生成される.
  • スコフ情報は、現在実行されている実行コンテキストで接続リストと同様に作成される.現在のコンテキストで変数にアクセスする必要がある場合は、このリストを使用します.このリストでは、現在のコンテキストの変数と親実行コンテキストの変数にアクセスできます.
  • は、リストをscopeチェーンと呼び、[scope]propertyとして参照する.現在生成されているアクティブなオブジェクトは、スキャンチェーンの一番前に追加されます.
  • 変数の作成

  • の次のステップでは、現在の実行コンテキスト内で使用されている領域変数が作成されます.生成された変数を格納する変数オブジェクトは、アクティブなオブジェクトが変数オブジェクトとして使用され、オブジェクトが同じオブジェクトです.
  • 変数オブジェクトで呼び出された関数パラメータは、各propertyを作成し、その値を割り当てます.値が割り当てられていない場合はundefinedが割り当てられます.そして、関数に定義された変数、関数が生成されます.このプロセスでは、メモリに変数または内部関数を作成するだけで、各変数または関数に対応する式を実行するまで初期化は行われません.したがって、まず変数に未定義の値が割り当てられます.
  • このバインディング

  • の最後のステップでは、このキーワードを使用する値が指定されます.ここにthisが参照するオブジェクトがない場合は、グローバルオブジェクトが参照されます.
  • 実行コード


    スキャンチェーン

  • JavaScriptでは、関数のみが有効範囲の単位です.この有効範囲を表すscopeは[scope]プログラムで、各関数オブジェクト内でscopeチェーンと呼ばれる接続リストとして管理されます.
  • スコフチェーンは、実行コンテキストの変数オブジェクト(アクティブオブジェクト)がコンポーネントであるリストと同じです.->自動スキャンチェーン[(3,...)、(2,変数オブジェクト2),(1,変数オブジェクト1),(0,変数オブジェクト0)]
  • の各関数は[scope]propertyであり、自身が生成した実行コンテキストのscopeチェーンを参照する.関数が実行されると、実行された関数の[scope]propertyに基づいて新しいscopeチェーンが作成される実行コンテキストが作成されます.
  • グローバル実行コンテキストのスキャンチェーン

    <script>
    var var1 = 1;
    var var2 = 2;
    console.log(var1); // (출력값) 1
    console.log(var2); // (출력값) 2
    </script>
    
    1) 위 코드는 전역 코드이다. 함수가 선언되지 않아 함수 호출이 없고, 실행 가능한 코드들만 나열되어 있다.
    2) 위 코드가 실행되면, 먼저 전역 실행 컨텍스트가 생성되고, 변수 객체가 만들어진다.
    3) 현재 전역 실행 컨텍스트 단 하나만 실행되고 있어 참조할 상위 컨텍스트가 없다. 자신이 최상위에 위치하는 변수 객체이다.
    4) 따라서, 이 변수 객체의 소코프 체인은 자기 자신만을 가진다.
    5) 변수 객체의 [[scope]]는 변수 객체 자신을 가리킨다.

    関数を呼び出すときに作成される実行コンテキストのブランチチェーン。

    <script>
    var var1 = 1;
    var var2 = 2;
    function func() {
        var var1 = 10;
        var var2 = 20;
        console.log(var1);  // (출력값) 10
        console.log(var2);  // (출력값) 20
    }
    func();
    console.log(var1);  // (출력값) 1
    console.log(var2);  // (출력값) 2
    </script>
    
    1) 코드 실행시 전역 실행 컨텍스트가 생성되고, func() 함수 객체가 만들어진다.
    2) 함수 객체가 생성될 때, 그 함수 객체의 [[scope]]는 현재 실행되는 컨텍스트의 변수 객체에 있는 [[scope]]를 그대로 가진다. 따라서, func 함수 객체의 [[scope]]는 전역 변수 객체가 된다.
    3) 스코프 체인[(1, func 변수 객체), (0, 전역 객체)]
  • 各関数オブジェクトは[scope]propertyであり、現在のコンテキストのscopeチェーンを参照します.
  • 個の関数を実行すると、現在実行中の関数オブジェクトの「範囲」propertyがコピーされ、新しく生成された変数オブジェクトがチェーンの一番前に追加される新しい実行コンテキストが作成されます.
  • レンジチェーン=現在の実行コンテキストの変数オブジェクト+親コンテキストのレンジチェーン
  • スキャンチェーンによって識別される.scopeチェーンの最初の変数オブジェクトから、識別子に対応する名前のpropertyがあるかどうかを確認します.変数オブジェクトの正式なパラメータ、内部関数、および領域変数を確認し、次のオブジェクトに移動して検索します.
  • レプリカ


    モジュールの概念

  • ライフサイクルが終了した外部関数の変数を参照する関数をcloserと呼びます.
  • <script>
    function outerFunc() {
        var x = 10;
        var innerFunc = function () { console.log(x); }
        return innerFunc;
    }
    
    var inner = outerFunc();
    inner();    // (출력값) 10
    </script>
    1) outerFunc에서 선언된 x를 참조하는 innerFunc가 클로저
    2) 클로저로 참조되는 외부 변수 즉, outerFunc의 x와 같은 변수를 '자유 변수'라고 한다. 클로저는 자유 변수에 엮여 있는 함수이다.
    
    <script>
    function  outerFunc(arg1, arg2) {
        var local = 8;
        function innerFunc(innerArg) {
            console.log((arg1 + arg2) / (innerArg + local))
        }
        return innerFunc;
    }
    var exam1 = outerFunc(2, 4);
    exam1(2);
    </script>

    エンクロージャの使用

    <script>
    var getCompletedStr = (function () {
        var buffAr = [
            'I am ',
            '',
            '. I live in ',
            '',
            '. I am ',
            '',
            ' years old.',
        ];
    
        return (function (name, city, age) {
            buffAr[1] = name;
            buffAr[3] = city;
            buffAr[5] = age;
    
            return buffAr.join('');
        });
    })();
    
    var str = getCompletedStr('zzoon','seoul', 16);
    console.log(str);
    </script>
    --> I am zzoon. I live in seoul. I am 16 years old.
    <script>
    function callLater(obj, a, b) {
        return (function () {
            obj["sum"] = a + b;
            console.log(obj["sum"]);
        });
    }
    
    var sumObj = {
        sum : 0
    }
    
    var func = callLater(sumObj, 1, 2);
    setTimeout(func, 2000);
    </script>
    --> 2초 뒤, 3
    <script>
    function outerFunc(argNum) {
        var num = argNum;
        return function (x) {
            num += x;
            console.log('num: ' + num);
        }
    }
    var exam = outerFunc(40);
    exam(5);
    exam(-10);
    </script>
    --> num : 45, num : 35
    - 클로저의 프로퍼티값이 쓰기 가능하므로 그 값이 여러 번 호출로 항상 변경할 수 있음
    <script>
    function func() {
        var x = 1;
        return {
          func1 : function () { console.log(++x); },
          func2 : function () { console.log(-x); }
        };
    };
    
    var exam = func();
    exam.func1();
    exam.func2();
    </script>
    --> 2, -2
    - 하나의 클로저가 여러 함수 객체의 스코프 체인에 들어가 있는 경우
    <script>
    function countSeconds(howMany) {
        for (var i = 1; i <= howMany; i++) {
            (function (currentI) {
                setTimeout(function () {
                    console.log(currentI);
                }, currentI * 1000);
            })(i);
        }
    };
    countSeconds(3);
    </script>
    --> 1, 2, 3