[JS]this-これは状況次第です


この文章.📕Core JavaScriptベースの記事です.
JavaScriptコードの作成には、thisがよく使用されます.thisの正しい働き方が分からないので、thisを使うのが好きではありません(これはなぜこの対象を見るのですか?)😫 疑問).
他のほとんどのオブジェクト向け言語では、thisはクラスが作成したインスタンスオブジェクトを表します.
JAvascriptのthisは、どこでも使用できるため、混乱を引き起こしやすいようです.thisの正しい動作方法について
何でも知ってから書こう!!

💡 状況次第だ


Javascriptでは、thisは基本的に実行コンテキストを作成するときに一緒に決定されます.
実行コンテキストは、関数を呼び出すときに生成され、言い換えれば、thisは、関数を呼び出すときに決定される.
つまり、関数がどのように呼び出されるかによって、値が異なります.

グローバルスペースのthis


グローバル空間では、thisはグローバルオブジェクトを指す.
概念的には、グローバルコンテキストを作成するボディがグローバルオブジェクトであるためです.

グローバルスペースのthis(ブラウザ環境)



📌 グローバル空間でのみ発生する特殊な性質.
グローバル変数を宣言すると、JavaScriptエンジンはグローバルオブジェクトのプロパティにも割り当てます.
つまり、変数であり、オブジェクトのプロパティでもあります.
var a = 1;
console.log(a); // 1
console.log(window.a); // 1
console.log(this.a); // 1
私はグローバル空間宣言の変数aに1を割り当てただけです.window.athis.aの両方が出力1
console.log(this);
上のコードからthisを出力します.
aがグローバルオブジェクトに割り当てられたpropertyが表示されます.

メソッドとして呼び出す場合、メソッド内部のthis


関数vs.メソッド


関数を実行する2つの最も一般的な方法
  • 関数呼び出し
  • メソッド呼び出し
  • この両者を区別する唯一の違いは独立性にある.
    関数自体が独立した機能を実行します.
    メソッドは、呼び出されたターゲットオブジェクトに関連する操作を実行します.
    JAvascriptは、異なる場合にthisキーワードに異なる値を付与することによって実現される.
    ¥¥¥¥
    オブジェクトとしてメソッドが呼び出された場合にのみメソッドとして動作し、そうでなければ関数として動作します.
    次の例を検証します.

    関数呼び出し、メソッド呼び出し

    var func = function (x) {
      console.log(this, x);
    };
    
    // (1) 함수로서의 호출
    func(1); // x=1
    
    var obj = {
      method: func,
    };
    
    // (2) 메서드로서의 호출
    obj.method(2); // x=2
  • (1)関数を呼び出した結果
  • (2)メソッド呼び出しの結果
  • (1)funcを呼び出すと、グローバルオブジェクトウィンドウがthisに出力されることがわかる.
    (2)objという変数にオブジェクトを割り当て,オブジェクトのメソッドプロセスでfunc関数を先に割り当てる.
    次いでobjのmethodが呼び出され、thisがobjを指す.
    すなわち、元の匿名関数が変わらず変数に含まれて呼び出され、objオブジェクトに割り当てられたpropertyが呼び出されると、thisが変更されます.

    関数として呼び出す方法とメソッドとして呼び出す方法を区別します。


    関数の前に点があるかどうかを簡単に区別するだけです(.).
    (もちろん、角カッコの場合はドメインとして呼び出されます)
    var obj = {
      method: function (x) {
        console.log(this, x);
      },
    };
    obj.method(1);
    obj['method'](2);

    メソッド内部のthis

    thisは、発呼主体に関する情報を含む.
    メソッドで関数を呼び出すと、呼び出し主体が関数名(property名)の前のオブジェクトになります.
    ポイントシンボルの場合、最後のポイントより前に指定されたオブジェクトはthisです.
    var obj = {
      methodA: function () {
        console.log(this);
      },
      inner: {
        methodB: function () {
          console.log(this);
        },
      },
    };
    
    obj.methodA();
    obj.inner.methodB();

    関数として呼び出されたときの関数内部のthis


    関数内部のthis


    関数として関数を呼び出す場合は、thisは指定されません.
    実行コンテキストが有効なときにthisが指定されていない場合、thisはグローバルオブジェクトを表示します.
    したがって、関数のthisはグローバルオブジェクトを指します.

    メソッドの内部関数のthis


    メソッドの内部定義と実行の関数のthisは何ですか.
    前述したように、内部関数も関数として呼び出されるかどうかが分かれば、thisの値を正確に求めることができる.
    var obj1 = {
      outer: function () {
        console.log(this); // (1)
        var innerFunc = function () {
          console.log(this); // (2) (3)
        };
        innerFunc();
    
        var obj2 = {
          innerMethod: innerFunc,
        };
        obj2.innerMethod();
      },
    };
    
    obj1.outer();

    以下の結果が得られた
    📌 すなわち,thisバインドでは,関数を実行する際の周囲環境(メソッド内部か関数内部かなど)は重要ではなく,関数を呼び出す構文の前に点や括弧マークがあるかどうかが鍵となる.

    コール時の周辺環境のthisは継承できませんか?


    変数を検索する場合は、まず最近のScopeのLEを検索し、ない場合は親Scopeを検索し、thisが現在のコンテキストのターゲットにバインドされていない場合は、前のコンテキストのthisを参照してください.
    ES 5までは内部関数からthisを継承することはできなかったが,それを迂回する方法があった.
    var obj = {
      outer: function () {
        console.log(this);
        var innerFunc1 = function () {
          console.log(this);
        };
        innerFunc1();
    
        var self = this;
        var innerFunc2 = function () {
          console.log(self); 
        };
        innerFunc2();
      },
    };
    obj.outer();

    上図に示すようにouter scopeでthisをself変数に保存して出力する方式です.

    このアイテムをバインドしない関数


    ES 6では,関数内部thisがグローバルオブジェクトを観察する問題を補うために,thisをバインドしない矢印関数(arrowfunction)を新たに導入した.
    矢印関数は、実行コンテキストの生成時にthisバインドプロセス自体が失われるため、親のthisを直接使用できます.
    つまり、上で説明した迂回方式を使う必要はありません!!
    var obj = {
      outer: function () {
        console.log(this);
        var innerFunc = () => {
          console.log(this);
        };
        innerFunc();
      },
    };
    obj.outer();

    コールバック関数を呼び出すと、関数内部のthis


    関数Aの制御権を他の関数(またはメソッド)Bに渡すと、関数Aはコールバック関数と呼ばれる.
    このとき、関数Aは、関数Bの内部論理に従って実行され、thisも、関数Bの内部論理で定義された規則に従って値を決定する.
    コールバック関数も関数であるため、デフォルトではthisがグローバルオブジェクトを参照しますが、制御された関数でコールバック関数の別のオブジェクトthisが指定されている場合は、そのオブジェクトを参照します.
    setTimeout(function () {
      console.log(this); // (1)
    }, 300);
    
    [1, 2, 3, 4, 5].forEach(function (x) {
      console.log(this, x); // (2)
    });
    
    document.body.innerHTML += '<button id="a">클릭</button>';
    document.body.querySelector('#a').addEventListener('click', function (e) {
      console.log(this, e); // (3)
    });

  • (1)の結果

    settimeout関数は、300 ms遅延後にコールバック関数を実行するコマンドです.0.3秒後にグローバルオブジェクトを出力

  • (2)の結果

    forEachメソッドは、配列内の各要素を前から順に取り出し、その値をコールバック関数の最初のパラメータとして関数として実行するコマンドです.
    グローバルオブジェクトと配列の要素ごとに5回出力

  • (3)の結果

    addEventListenerは、指定された領域で「click」イベントが発生した場合に、そのイベント情報をコールバック関数の最初のパラメータとして関数を実行するコマンドです.
    ボタンをクリックすると、指定したエンティティとイベント関連情報を含むオブジェクトが出力されます.
  • 📌 (1)のsettimeoute関数および(2)のforEachメソッドは、内部コールバック関数を呼び出すときにターゲットthisを指定しない.したがって、thisはグローバルオブジェクトを参照する
    一方(3)のaddEventListenerメソッドは,コールバック関数を呼び出すときに自身のthisを継承すると定義する.すなわち、点(.)の前部はthis!

    コンストラクション関数のthis


    コンストラクション関数は、いくつかの共通の性質を持つオブジェクトを作成するための関数です.
    オブジェクト向け言語では、ジェネレータをクラス、クラスで作成されたオブジェクトをインスタンスと呼びます.
    JAvascriptは関数を構築関数として与える役割を果たす.newコマンドとともに関数が呼び出されると、その関数はコンストラクション関数として動作します.
    さらに、ある関数がコンストラクション関数として呼び出されると、内部のthisは、新しく作成された特定のインスタンス自体となる.
    var Cat = function (name, age) {
      this.bark = '야옹';
      this.name = name;
      this.age = age;
    };
    var ddong = new Cat('뚱이', 7); // (1)
    var coco = new Cat('코코', 6); // (2)
    console.log(ddong, coco);

    Catという名前の変数には匿名関数が割り当てられている.
    この関数の内部では、bark、name、age propertyにそれぞれ値を割り当てるthisにアクセスします.
    次いで、new命令とともにCat関数が呼び出され、変数ddong、cocoにそれぞれ割り当てられる.
    すなわち、(1)で実行されるコンストラクタ内部のthisはddongインスタンスを示す.
    (2)で実行されるコンストラクタ内部のthisは、cocoの例を表す.