第22章


この欄


まず、コンストラクション関数によってインスタンスを作成する例を見てみましょう.
function Circle(radius) {
  // 이 시점에는 생성자 함수 자신이 생성할 인스턴스를 가리키는 식별자를 알 수 없다.
  ???.radius = radius;
}

const circle = new Circle(5);
コンストラクション関数を定義するときにインスタンスが作成されていないため、コンストラクション関数は作成するインスタンスを指す識別子を認識できません.このためjavascriptには、thisという特殊な識別子が提供され、自分が属するオブジェクトまたは自分が作成するインスタンスを指すことができます.thisはjavascriptエンジンによって暗黙的に生成され、関数を呼び出すと暗黙的に関数内部に渡されます.その後、thisは、関数内部で領域変数のように使用することができる.thisは、自分が属するオブジェクトまたは作成するインスタンスを指す自己参照変数(self-reference変数)です.

関数呼び出しとバインド

thisが指す値を表すこのバインディングは、関数呼び出し方式によって動的に決定される.
関数は、さまざまな方法で呼び出すことができます.
呼び出し
  • 一般関数
  • メソッド呼び出し
  • 呼び出し
  • ジェネレータ関数
  • Function.prototype.apply/call/bindメソッドによる間接呼び出し
  • 各コール方式のthis 바인딩を見てみましょう.

    一般関数の呼び出し


    デフォルトでは、thisはグローバルオブジェクトをバインドします.
    // 전역 함수
    function foo() {
      console.log("foo's this: ", this); // window
      
      // 중첩 함수
      function bar() {
        console.log("bar's this: ", this); // window
      }
      
      bar();
    }
    
    foo();
    グローバル関数だけでなく、ネストされた関数も通常の関数として呼び出されると、関数内部のthisがグローバルオブジェクトをバインドします.
    function foo() {
      // strict mode 적용
      'use strict'; 
      
      console.log("foo's this: ", this); // undefined
      
      function bar() {
        console.log("bar's this: ", this); // undefined
      }
      
      bar();
    }
    
    foo();
    しかし、strict modeを適用する一般的な関数の内部のthisはundefinedにバインドされる.thisは、オブジェクトを参照するためのPropertyまたはメソッドの自己参照変数であるため、オブジェクトを作成しない通常の関数では意味がありません.
    コールバック関数も通常の関数として呼び出されると、グローバルオブジェクトがバインドされます.
    // 전역 변수
    var value = 1;
    
    const obj = {
      value: 100,
      foo() {
        console.log("foo's this: ", this); // {value: 100, foo: f}
        
        // 콜백 함수
        setTimeout(function() {
          console.log("callback's this: this", this); // window
          console.log("callback's this.value: ", this.value); // 1
        }, 100);
      }
    };
    
    obj.foo();
    上記の例では、ドメイン内でsetTimeout関数に渡されるコールバック関数のthisにグローバルオブジェクトがバインドされる.したがって、this.valueは、objオブジェクトのvalueではなく、グローバルオブジェクトのwindow.valueを参照する.
    コールバック関数のthisobjオブジェクトのvalueとどのようにマッチングしますか?
    📙 1.このバインディングを割り当てる
    var value = 1;
    
    const obj = {
      value: 100,
      foo() {
        const that = this;
        console.log(that); // {value: 100, foo: f}
        
        setTimeout(function() {
          console.log(that.value); // 100
        }, 100);
      }
    };
    
    obj.foo();
    このバインディングが変数thatに割り当てられる場合、コールバック関数の内部ではthisではなくthatを参照することができる.
    📙 2. Function.prototype.bind()
    さらにjavascriptは、thisを明示的にバインドする機能も有する.prototype.bindメソッドを提供します.
    var value = 1;
    
    const obj = {
      value: 100,
      foo() {
        setTimeout(function() {
          console.log(this.value); // 100
        }.bind(this), 100);
      }
    };
    
    obj.foo();
    📙 3.矢印関数
    矢印関数を使用して、thisバインドを一致させることができます.
    var value = 1;
    
    const obj = {
      value: 100,
      foo() {
        setTimeout(() => console.log(this.value), 100); // 100
      }
    };
    
    obj.foo();

    メソッド呼び出し


    メソッド内のthisは、メソッドのオブジェクトではなく呼び出しメソッドにバインドされます.
    const person = {
      name: 'Lee',
      getName() {
        return this.name;
      }
    };
    
    console.log(person.getName()); // Lee
    方法はプログラムにバインドされた関数です.personオブジェクトのgetNameパーセントで表される関数オブジェクトは、personオブジェクトに含まれるのではなく、独立して存在する独立したオブジェクトです.getName Propertyは、関数オブジェクトのみを指します.

    したがって、getNameメソッドは、getNameプロパティが指す関数オブジェクトであり、別のオブジェクトのプロパティに割り当てられ、別のオブジェクトのメソッドであっても、通常の変数に割り当てられ、通常の関数として呼び出されます.
    const person = {
      name: 'Lee',
      getName() {
        return this.name;
      }
    };
    
    const anotherPerson = {
      name: 'Kim'
    };
    // anotherPerson 객체에 할당
    anotherPerson.getName = person.getName;
    
    console.log(anotherPerson.getName()); // Kim
    
    // 변수에 할당
    const getName = person.getName;
    
    console.log(getName()); // ''
    getNameメソッドをanotherPersonオブジェクトのメソッドとして指定し、anotherPersonオブジェクトのgetNameメソッドを呼び出し、結果として「Lee」ではなく「Kim」が表示されます.
    また、一般関数によって呼び出されるgetName関数内部のthis.nameは、ブラウザ環境においてwindow.nameと同じである.ブラウザ環境では、window.nameはブラウザウィンドウの名前を表し、デフォルト値は''です.
    このように、メソッド内部のthisは、propertyとしてメソッドを指すオブジェクトとは無関係に、呼び出しメソッドのオブジェクトにバインドされる.

    コンストラクタの呼び出し


    コンストラクション関数内部のthisでは、コンストラクション関数によって生成されるインスタンスをバインドします.
    function Circle(radius) {
      this.radius = radius;
      this.getDiameter = function () {
        return 2 * this.radius;
      };
    }
    
    // 생성자 함수로 호출
    const circle1 = new Circle(5);
    console.log(circle1.getDiameter()); // 10
    
    // 일반 함수로 호출
    const circle2 = Circle(10);
    console.log(circle2); // undefined
    第17章構築関数で見たように、new演算子とともに呼び出されると、この関数はコンストラクション関数として動作し、new演算子とともにコンストラクション関数を呼び出さなければ、通常の関数として動作する.通常の関数を使用する場合、Circle関数には文が返されないため、デフォルトでは定義されていません.

    apply/call/bind()呼び出し

    applycallbindの方法はFunction.prototypeの方法であるので、これらの方法はすべての関数によって継承されて使用することができる.applycallメソッドは、使用するオブジェクトを受信し、関数を呼び出す.
    function getThisBinding() {
      return this;
    }
    
    // this로 사용할 객체
    const thisArg = { a: 1 };
    
    console.log(getThisBinding()); // window
    
    console.log(getThisBinding.apply(thisArg)); // { a: 1 }
    console.log(getThisBinding.call(thisArg)); // { a: 1 }
    this関数を呼び出し、パラメータとして渡されたオブジェクトをgetThisBinding関数のgetThisBindingにバインドします.
    これとは異なり、thisメソッドは関数を呼び出さず、bindとして使用されるオブジェクトのみを渡す.
    function getThisBinding() {
      return this;
    }
    
    // this로 사용할 객체
    const thisArg = { a: 1 };
    
    console.log(getThisBinding.bind(thisArg)); // getThisBinding
    
    console.log(getThisBinding.bind(thisArg)()); // { a: 1 }
    thisメソッドは、bindとして使用するオブジェクトのみを関数に渡すため、関数を呼び出さずに明示的に呼び出さなければならない.
    これまで,関数呼び出し方式によるthisバインドの決定について議論した.以下に整理します!
    関数呼び出しメソッドこのバインド汎用関数呼び出しグローバルオブジェクトメソッド呼び出しのオブジェクトジェネレータ関数番号生成構造関数は、インスタンスアプリケーション/call/bind()呼び出しアプリケーション/call/bind()メソッドのオブジェクトをパラメータとしてパラメータに渡す