This

15563 ワード

開始前


実際,関数式プログラミングを熟知しreitの関数素子を徐々に普及させている場合,これはめったに見られない.
しかし、それでもオブジェクト向けの開発は伝統的なものではなく、角度や部分的にオブジェクト向けのデータベース(ex,typeORM)を見る場合、それに直面するのは必然であり、面接でもよく聞かれるので、整理した概念で書く.

🚍 1.これは


オブジェクト向けの開発では,オブジェクトには大きく2つの形態がある.
1.ステータス:オブジェクトの内部に存在するステータスプロセスは、そのオブジェクトが持つ固有のデータである
2.動作:オブジェクト内部に存在する方法はCRUDオブジェクト状態の関数である
この場合,この関連部分は「動作」に相当する方法である.
この操作に関連するメソッドは、ステータスを変更するために、このステータスプロセスを含むオブジェクトにアクセスできる必要があります.
もちろん、オブジェクト自体が文字形式の場合は、オブジェクトにバインドされた識別子を参照するだけでよい.
const obj = {
   state : 1,
   action() {
      obj.state += 1;
   }
}

obj.action(); 
// 이 메서드가 호출되는 시점에는 이미 obj의 식별자 정의가 완료되고, 
//이 식별자에 평가완료된 객체 리터럴의 레퍼런스 주소가 바인딩된 상태이기 때문에 동작이 가능하다.
しかし,オブジェクト向け開発の最大の機能は,コンストラクション関数により継承実現を完了するオブジェクトを生成することである.
function Obj (stateValue) {
   인스턴스.state = stateValue;
}

Obj.prototype.action = function(){
   인스턴스.state += 1;
}

const obj = new Obj(1);
// 이 코드가 실행될 당시의 실행 컨텍스트를 생각해보자
// function Obj는 함수객체로 평가가 된 상태고, 이 객체의 prototype에 상속가능한 프로토타입 메서드 "action"이 할당된 상태이다.
// new 문이 실행되면 뒤에 정의된 생성자 함수를 호출하면서 암묵적으로 임시 인스턴스 객체를 만들어 메모리에 저장한 후, 그 객체 내부를 
// 생성자 함수의 정의에 따라 초기화시켜야 한다.
// 여기서 문제점은, 방금 전 object literal 때와는 다르게 생성자 함수가 미래에 만들어질 인스턴스를 초기화시키기 위해서는
// 필수적으로 이 미래에 생성될 인스턴스를 지칭할 식별자가 필요하다. 여기서 바로 this의 필요성이 존재하는 것이다.
すなわち、thisはインスタンスの初期化時にコンストラクション関数が作成するインスタンスを指定する「自己参照変数」です.

🚍 2.このバインディング


関数を呼び出すときに作成される実行コンテキストでは、argumentsという類似配列オブジェクトが自動的に定義されます.
このときthisの定義方式は動的に決定され,区別が必要である.

a.一般関数の呼び出し


通常関数として呼び出されると、関数実行コンテキストにバインドされたthisはグローバルオブジェクトwindowになります.
function global () {
 console.log(this);
}

global() // window객체
ただし、strictモードでコードが実行されるとundefinedを指します.
これはsettimeoutのような非同期関数呼び出し内のコールバック関数で定義されていても、通常の関数呼び出しと同じプロセスを経験します.
コールバック関数はテクノロジーキューにあるため、callstekが空の場合、直接入力され、通常の関数として実行されます.

b.オブジェクトメソッドとして呼び出す

const obj = {
   action(){
     console.log(this);
   }
}

obj.action() // obj 객체
この場合、メソッド呼び出し時にcallstekに格納されるメソッドの実行コンテキストthisでは、関数オブジェクトがバインドされて定義される.
Prototypeで定義されたメソッドが呼び出されると、そのメソッドが呼び出されるオブジェクトPrototypeオブジェクトになります.
function Test () {
   this.name = "a";
}

Test.prototype.name = "b";

Test.prototype.getName = function () {
   console.log(this.name);
}

const obj = new Test();
obj.getName(); // "a"
Test.prototype.getName(); // "b"

c.コンストラクタとして呼び出す


このとき、コンストラクション関数の実行コンテキスト内に渡されるthisは、new文が暗黙的に生成したインスタンスのアドレスにバインドされます.
ちなみに、このインスタンスの内部構造は以下の通りです.
function Construction(){
   this.name = "hello"
}

const obj = new Construction(); 
// 이때 생성되는 임시 인스턴스 내부에는 [prototype] 슬롯이 존재한다
// 이 슬롯 내부에 바인딩되는 객체에는 "constructor" 프로퍼티가 존재하고, 이것은 생성자 함수를 가리킨다 (Construction)

d.bind/call/applyを呼び出す


関数オブジェクトのプロトタイプスロットに存在する機能.prototypeオブジェクトには、コンストラクション関数機能から継承された複数のタイプのprototypeメソッドがあります.
開発者は、関数を呼び出すときに実行コンテキストで投げ出すthisを直接決定できるバインド、呼び出し、および適用方法があります.
簡単に区別すると.
bindは、関数で変更された関数を返します.
applyとcallは、このバインドをパラメータとして渡されたオブジェクトとして使用し、ターゲット関数を呼び出します.
applyは配列を2番目のパラメータに渡し、パラメータに割り当てます.
callは、2番目からリストされたパラメータをargumentsのproperty値に順次バインドし、呼び出し関数の違いがあります.
bindの構造は次のようにCloserの概念で実現される.
// 1. 일반 함수를 정의한다.
function test () {
 return this // 이대로 test를 호출하면 strict mode일 경우 undefined가 된다
}

// 2. test 함수객체의 prototype에 bind를 정의한다. ( 함수객체의 prototype 프로퍼티 객체 내부 [Function.prototype] 내부 메서드 bind를 오버라이딩 하는 용도 )
test.prototype.bind = function (thisTarget) {
    return (...args) => this.apply(thisTarget, args); 
    // 해당 bind 함수 내에서 바인딩되는 this는 함수객체 test이다.
    // apply의 정의에 따라 첫째 인자로 this가 될 대상을, 둘째 인자로 함수가 호출되면서 전달할 arguments 대상의 배열을 전달하면 된다.
}

const parentProto = {name : "Anderson"};

const updatedFunc = test.bind(parentProto);  // (...args) => this.apply(thisTarget, args); 
spread構文が現れる前に、数の不確定なパラメータを処理する必要がある場合、パラメータ類似配列オブジェクトで関数プロトタイプメソッドを使用するためにapplyとcallが使用されることが多い.
function coverArgs (){
   const arr1 = Array.prototype.slice.call(arguments); // Array 의 프로토타입 메서드들은 this가 해당 호출대상인 배열이므로 arguments와 같은 유사배열객체가 해당 메서드를 사용하려면 이렇게 call을 통해 this로 전달하면서 사용하면 된다.

   const arr2 = [...arguments].slice(); // es6 스프레드 문법 업데이트 이후는 이렇게 간결하게 사용 가능하다.
}

矢印関数の場合


このような複雑なthisの場合、es 6以降に導入された矢印関数にはthisバインドは存在せず、親実行コンテキストのthisを常に参照します.
const value = 100;

const obj = {
   foo (){
      setTimeout(()=> console.log(this), 100) 
   }
}

obj.foo() // obj
// 위의 경우, 화살표 함수가 아니라면 setTimeout의 콜백함수는 일반함수호출이 되므로 this는 window가 될 것이다.
// 그러나 화살표 함수는 무조건 상위 컨텍스트에 정의된 this를 사용하므로, 이때의 this는 foo함수의 this, 즉 obj가 된다.