📌 第22章



🌺 22.1このキーワード


これは、所属するオブジェクトまたは作成するインスタンスを指す自己参照変数です.これにより、オブジェクトまたは作成するインスタンスに属するプロシージャまたはメソッドを参照できます.
これはJavaScriptエンジンによって暗黙的に生成され、コードはどこでも参照できます.関数を呼び出すとargumentsオブジェクトとそれは黙って関数の内部に渡されます.関数内でargumentsオブジェクトを領域変数として使用できるように、領域変数としても使用できます.しかし、thisが指す値(すなわち、thisバインド)は、関数呼び出しによって動的に決定されます.
これは、オブジェクトを参照するためのPropertyまたはメソッドの自己参照変数であり、通常はオブジェクトのメソッド内部またはコンストラクション関数内部にのみ意味があります.従ってstrict modeを適用した一般的な関数の内部では,thisはundefinedをバインドした.一般的な関数の内部ではthisを使用する必要はありません.
🧐 このバインディング
バインドは、識別子と値を関連付けるプロセスを意味します.たとえば、変数宣言は、変数名(識別子)と保存済みメモリ領域をバインドするアドレスです.thisバインドは、thisとthisが指すオブジェクトのバインドです.

🌺 22.2関数の呼び出しとバインド


このバインド(この値にバインドされる)は、関数が呼び出される方法(すなわち、関数がどのように呼び出されるか)によって動的に決定されます.
関数の呼び出し方法は次のとおりです.関数の呼び出し方法がこのバインドをどのように決定するかを見てみましょう.
呼び出し
  • 一般関数
  • メソッド呼び出し
  • 呼び出し
  • ジェネレータ関数
  • Function.prototype.apply/call/bindメソッドによる間接呼び出し
  • 🧐 Lexicalscopeとthisバインドの決定時間は異なります.
    関数の親スキャンを決定する方法は、関数定義が評価され、関数オブジェクトの作成時に親スキャンが決定されます.ただし、このバインドは関数呼び出し時に決定されます.

    22.2.1一般関数の呼び出し


    デフォルトでは、thisはグローバルオブジェクトをバインドします.通常の関数で呼び出されるすべての関数(ネスト関数とコールバック関数を含む)の内部で、thisはグローバルオブジェクトをバインドします.
    // var 키워드로 선언한 전역 변수 value는 전역 객체의 프로퍼티다.
    var value = 1;
    // const 키워드로 선언한 전역 변수 value는 전역 객체의 프로퍼티가 아니다.
    // const value = 1;
    
    const obj = {
      value: 100,
      foo() {
        console.log("foo's this: ", this);  // {value: 100, foo: ƒ}
        console.log("foo's this.value: ", this.value); // 100
    
        // 메서드 내에서 정의한 중첩 함수
        function bar() {
          console.log("bar's this: ", this); // window
          console.log("bar's this.value: ", this.value); // 1
        }
    
        // 메서드 내에서 정의한 중첩 함수도 일반 함수로 호출되면 중첩 함수 내부의 this에는 전역 객체가 바인딩된다.
        bar();
      }
    };
    
    obj.foo();
    メソッド内のネスト関数またはコールバック関数のthisバインドとメソッドのthisバインドを一致させる方法は、次のとおりです.
    var value = 1;
    
    const obj = {
      value: 100,
      foo() {
        // this 바인딩(obj)을 변수 that에 할당한다.
        const that = this;
    
        // 콜백 함수 내부에서 this 대신 that을 참조한다.
        setTimeout(function () {
          console.log(that.value); // 100
        }, 100);
      }
    };
    
    obj.foo();

    22.2.2メソッド呼び出し


    メソッドの内部にあるthisは、メソッドが持つオブジェクトではなく、メソッドを呼び出すオブジェクトにバインドされます.
    const person = {
      name: 'Lee',
      getName() {
        // 메서드 내부의 this는 메서드를 호출한 객체에 바인딩된다.
        return this.name;
      }
    };
    
    // 메서드 getName을 호출한 객체는 person이다.
    console.log(person.getName()); // Lee
    
    const anotherPerson = {
      name: 'Kim'
    };
    // getName 메서드를 anotherPerson 객체의 메서드로 할당
    anotherPerson.getName = person.getName;
    
    // getName 메서드를 호출한 객체는 anotherPerson이다.
    console.log(anotherPerson.getName()); // Kim
    
    // getName 메서드를 변수에 할당
    const getName = person.getName;
    
    // getName 메서드를 일반 함수로 호출
    console.log(getName()); // ''
    // 일반 함수로 호출된 getName 함수 내부의 this.name은 브라우저 환경에서 window.name과 같다.
    // 브라우저 환경에서 window.name은 브라우저 창의 이름을 나타내는 빌트인 프로퍼티이며 기본값은 ''이다.
    // Node.js 환경에서 this.name은 undefined다.

    22.2.3構造関数の呼び出し


    コンストラクション関数の内部にあるthisでは、コンストラクション関数は作成するインスタンスをバインドします.
    // new 연산자와 함께 호출하지 않으면 생성자 함수로 동작하지 않는다. 즉, 일반적인 함수의 호출이다.
    const circle3 = Circle(15);
    
    // 일반 함수로 호출된 Circle에는 반환문이 없으므로 암묵적으로 undefined를 반환한다.
    console.log(circle3); // undefined
    
    // 일반 함수로 호출된 Circle 내부의 this는 전역 객체를 가리킨다.
    console.log(radius); // 15

    22.2.4 Function.prototype.apply/call/bindメソッドによる間接呼び出し


    apply、call、bindはFinctioです.prototypeのメソッドなので、すべての関数を継承して使用できます.
    applyとcallメソッドの本質的な機能は呼び出し関数である.呼び出す関数の引数をパッケージ化して配列/リストに渡します.
    function getThisBinding() {
      console.log(arguments);
      return this;
    }
    
    // this로 사용할 객체
    const thisArg = { a: 1 };
    
    // getThisBinding 함수를 호출하면서 인수로 전달한 객체를 getThisBinding 함수의 this에 바인딩한다.
    // apply 메서드는 호출할 함수의 인수를 배열로 묶어 전달한다.
    console.log(getThisBinding.apply(thisArg, [1, 2, 3]));
    // Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
    // {a: 1}
    
    // call 메서드는 호출할 함수의 인수를 쉼표로 구분한 리스트 형식으로 전달한다.
    console.log(getThisBinding.call(thisArg, 1, 2, 3));
    // Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
    // {a: 1}
    
    function convertArgsToArray() {
      console.log(arguments);
    
      // arguments 객체를 배열로 변환
      // Array.prototype.slice를 인수없이 호출하면 배열의 복사본을 생성한다.
      const arr = Array.prototype.slice.call(arguments);
      // const arr = Array.prototype.slice.apply(arguments);
      console.log(arr);
    
      return arr;
    }
    
    convertArgsToArray(1, 2, 3); // [1, 2, 3]
    Functioin.prototype.applyメソッドとcallメソッドとは異なり、bindメソッドは関数を呼び出すのではなく、最初の引数として渡された値を使用してバインドを置き換えた関数を再作成し、返します.
    function getThisBinding() {
      return this;
    }
    
    // this로 사용할 객체
    const thisArg = { a: 1 };
    
    // bind 메서드는 첫 번째 인수로 전달한 thisArg로 this 바인딩이 교체된
    // getThisBinding 함수를 새롭게 생성해 반환한다.
    console.log(getThisBinding.bind(thisArg)); // getThisBinding
    // bind 메서드는 함수를 호출하지는 않으므로 명시적으로 호출해야 한다.
    console.log(getThisBinding.bind(thisArg)()); // {a: 1}
    bind法は,メソッドthisがメソッド内部のネスト関数またはコールバック関数thisと一致しない問題を解決するために用いられる.コールバック関数の内部のこの点は、外部関数の内部のこの点と一致しなければならない.
    const person = {
      name: 'Lee',
      foo(callback) {
        // ①
        setTimeout(callback, 100);
      }
    };
    
    person.foo(function () {
      console.log(`Hi! my name is ${this.name}.`); // ② Hi! my name is .
      // 일반 함수로 호출된 콜백 함수 내부의 this.name은 브라우저 환경에서 window.name과 같다.
      // 브라우저 환경에서 window.name은 브라우저 창의 이름을 나타내는 빌트인 프로퍼티이며 기본값은 ''이다.
      // Node.js 환경에서 this.name은 undefined다.
    });
    
    const person = {
      name: 'Lee',
      foo(callback) {
        // bind 메서드로 callback 함수 내부의 this 바인딩을 전달
        setTimeout(callback.bind(this), 100);
      }
    };
    
    person.foo(function () {
      console.log(`Hi! my name is ${this.name}.`); // Hi! my name is Lee.
    });

    このバインディングは、❗関数の呼び出し方法により、以下のようになります。



    Ref
    https://velog.io/@minj9_6/JavaScript-Core-Keyword-This