[TIL#29]このバインディング


JavaScriptを学ぶ際には、必ず知っておくべき概念でこの点を言及することがよくあります.ただし、JavaScriptのthisは他の言語の動作とは少し異なり、JavaScriptの関数の呼び出し方法によっては他のオブジェクトがバインドされるため、最初の表示では難しいと考えられる場合があります.しかし、これは必須の概念であり、私たちは必ず理解しなければならない.🏃‍♂️
(本文は内部JavaScript一書を読み、学習し、整理した)
これは何ですか.
このコンテキストバインドについて議論する前に、このコンテキストバインドが何であるかを理解してください.
thisは、コンストラクション関数またはメソッドでオブジェクトを指すときに使用されるキーワードです.
  • 新規オブジェクトに作成者の属性を入れる場合
  • オブジェクトにアクセスするプロパティ
  • 1.オブジェクトのメソッドを呼び出すときにこのメソッドをバインドする
    メソッドとは、オブジェクトのプロパティが関数である場合、この関数をメソッドと呼びます.
    このメソッドを呼び出すと、メソッド内で使用されるthisがメソッドを呼び出すオブジェクトにバインドされます.
    サンプルコード
    var firstObject = {
      name: 'first',
      sayName: function () {
        console.log(this.name);
      }
    };
    
    var secondObject = {
      name: 'second'
    };
    
    secondObject.sayName = firstObject.sayName;
    
    // sayName() 메서드 호출
    firstObject.sayName();	// first
    secondObject.sayName();	// second
    firstObjectおよびsecondObjectオブジェクトは、namepropertyおよびsayName()メソッドを有する.
    前述したように、メソッドは、メソッドを呼び出すオブジェクトにバインドされる.firstObject.sayName();では、firstObjectオブジェクト呼び出しsayName()メソッドであるため、ここではfirstObjectオブジェクトである.secondObject.sayName();では、secondObjectオブジェクト呼び出しsayName()メソッドであるため、ここではsecondObjectオブジェクトである.
    2.関数の呼び出し時にこの関数をバインドする
    関数を呼び出すと、関数の内部コードで使用されるthisがグローバルオブジェクトにバインドされます.
    (ブラウザでJavaScriptを実行すると、グローバルオブジェクトはwindowオブジェクトになります)
    燒グローバルオブジェクトとは、常にグローバル範囲内に存在するオブジェクトです.MDN
    サンプルコード
    var test = "This is test";	// 전역변수 선언
    console.log(window.test);	// This is test
    
    var sayFoo = function () {
      console.log(this.test);	// 결국 window.test를 의미한다
    };
    
    sayFoo();	// This is test
  • testグローバル変数windowグローバルオブジェクトとしてのpropertyアクセス
  • sayFoo()関数で使用されるthisはグローバルオブジェクトにバインドされるため、sayFoo()が呼び出されると、thisはグローバルオブジェクトwindowにバインドされる.
  • 3.コンストラクション関数の呼び出し時にこの関数をバインドする
    JavaScriptでオブジェクトを作成する方法は、1. 객체 리터럴 방식2. 생성자 함수 이용の2つです.
    コンストラクション関数を呼び出すと、コンストラクション関数コードの内部でthisはコンストラクション関数生成のオブジェクトにバインドされます.この点を理解するには、まず、コンストラクション関数が呼び出されたときの動作を理解します.
    ジルコニアジェネレータ関数の動作new演算子を使用してJavaScript関数をコンストラクション関数として呼び出し、以下の手順で操作します.
    1.空のオブジェクトを作成してバインドする
    ジェネレータ関数コードが実行される前に、空のオブジェクトが作成され、このオブジェクトにバインドされます.したがって、後でコンストラクション関数のコード内で使用されるthisは、この空のオブジェクトを指します.
    (厳密には、オブジェクトは空のオブジェクトではなく、そのプロトタイププロファイルが指すオブジェクトを独自のプロトタイププロファイルに設定します)
    2.ここからPropertyを作成する
    関数コードの内部では、thisを使用して前に作成した空のオブジェクトにプロパティやメソッドなどを動的に作成できます.
    3.作成したオブジェクトを返します
    文が返されない場合は、このバインドで新しく作成されたオブジェクトが返されます.戻り文が個別に存在し、他のオブジェクトが返される場合、返されるオブジェクトはthisではありません.
    オブジェクト文字vsコンストラクション関数
    // 객체 리터럴 방식으로 객체 생성
    var me = {
      name: 'minkyoung',
      age: 26
    };
    
    // 생성자 함수로 객체 생성
    function Person(name, age) {
      this.name = name;
      this.age = age;
    }
    
    // 같은 형태의 객체를 재생성할 수 있다
    var test = new Person('test', 20);
    var foo = new Person('foo',22);
    
    console.log(test.name);	// test
    console.log(foo.name);	// foo
    newがない場合にコンストラクション関数が呼び出されると、通常の関数が呼び出されます.この場合、この関数はwindowグローバルオブジェクトにバインドされます.
    4.apply、callを使用してこの項目を明示的にバインド
    前述したthisバインドは、関数呼び出しが発生したときに状況に応じて自動的にバインドできます.今回は、apply()メソッドとcall()メソッドを可能にするために、特定のオブジェクトに明示的にバインドする方法について説明します.
    (call()メソッドはapply()メソッドと機能は同じですが、パラメータのフォーマットが異なるだけです)function.apply(thisArg, argArray)と同じフォーマットでapply()メソッドを呼び出すことができます.
    呼び出し方式から見ると、呼び出しapply()メソッドの主体は関数であり、apply()メソッドも特定のオブジェクトにバインドされ、その本質的な機能は関数呼び出しである.
    最初のパラメータthisArgは、関数にバインドするthisのオブジェクトを指します.
    2番目のパラメータargArrayは、関数を呼び出すときに渡されるパラメータの配列です.
    要するに、apply()メソッドは、その関数を呼び出すパラメータとしてargArray配列を使用し、この関数の内部で使用されるthisはthisArgオブジェクトにバインドされて関数を呼び出す.
    サンプルコード
    // 생성자 함수
    function Person(name, age) {
      this.name = name;
      this.age = age;
    }
    
    // me 빈 객체 생성
    var me = {};
    
    Person.apply(me, ['minkyoung',26]);
    上のmeオブジェクトは、文字で作成された空のオブジェクトであり、apply()メソッドを使用してPerson('minkyoung', 26)関数を呼び出し、meオブジェクトに明示的にバインドします.
    call()メソッドはapply()メソッドと同じ機能を持つが,apply()で2番目のパラメータに渡される配列形式をそれぞれ1つのパラメータに渡す.上記の例をcall()メソッドに変更すると、次のようになります.Person.call(me, 'minkyong', 26);apply()メソッド、call()メソッドは、主に類似配列オブジェクトに配列メソッドを書き込むために使用されます.
    ❗ES 6に新しく追加されたArrayでもあります.「from()」メソッドを使用して、類似配列オブジェクトまたは重複可能オブジェクトをより浅い位置にコピーして、新しいオブジェクトを作成します.MDN
    5.イベントハンドラを呼び出すときにバインド
    イベントハンドラでは、イベントを受信するHTML要素にバインドされます.
    サンプルコード
    var btn = document.querySelector("#btn");
    btn.addEventListener('click', function () {
      console.log(this);	// #btn
    };
    6.矢印関数の呼び出し時にこの関数をバインドする
    上記の一般関数を呼び出す場合のthisのバインドは、矢印関数を呼び出す場合のthisのバインドと大きく異なります.
    グローバルオブジェクトにバインドされた通常の関数のthisとは異なり、矢印関数は最近のscopeに存在するthisバインドに従います.
    サンプルコード
    const minkyoung = {
      name: 'minkyoung',
      happy: true,
      printHobby: function() {
        const game = "game";
        let hobby = game;
        
        function checkHappy() {
          if(this.happy) hobby += " is funny";
          return hobby;
        }
        return `minkyoung's hobby : ${checkHappy()}`;
      }
    }
    
    minkyoung.printHobby(); 	// minkyoung's hobby : game
    このコードでは、thisがwindowを指しているため、happy: trueが理解できず、予想通りに出力できません.
    矢印関数を使用して同じコードを記述する場合は、次のようになります.
    const minkyoung = {
      name: 'minkyoung',
      happy: true,
      printHobby: function() {
        const game = "game";
        let hobby = game;
        
        let checkHappy = () => {
          if(this.happy) hobby += " is funny";
          return hobby;
        }
        return `minkyoung's hobby : ${checkHappy()}`;
      }
    }
    
    minkyoung.printHobby(); 	// minkyoung's hobby : game is funny
    このコードは矢印関数を使用するため、printHobbyの手順に従ってminkyoungオブジェクトをバインドします.
    矢印関数の注意事項
    const person = {
      name: "minkyoung",
      print: () => console.log(this.name)
    };
    person.pirnt();	// 에러 발생
    これは、メソッドを呼び出すオブジェクトではなく親コンテキストのグローバルオブジェクトをバインドしているため、エラーを引き起こします.
    これらの特性のため、オブジェクトの方法を矢印関数として使用するのは適切ではないことを知っておく必要があります!!
    参考資料
    参考資料