プロトタイプとは?

11699 ワード

プロトタイプの概念を学習し,どこで使用するかわからなかったが,学習の過程で構造関数とDOMの継承過程でプロトタイプが再び言及され,DOM操作を例にプロトタイプを整理しようとした.

プロトタイプとは?


まず、プロトタイプとは何ですか?
原型を理解するには、次の2つのゲート港を理解するだけでいいです.
  • オブジェクトがオブジェクトの親として機能する
  • JSで継承を実現する仕組み
  • この2つの問題を理解するには,まず継承の概念を分析する必要がある.

    継承とは?


    継承とは、あるオブジェクトのpropertyまたはメソッドが別のオブジェクトによって継承され、使用できることを意味します.
    では、なぜ継承し、継承して何がいいのでしょうか.

    すべてのインスタンスにメソッドがある場合:

    // 생성자 함수
    function Circle(radius) {
      this.radius = radius;
      this.getArea = function () {
        return Math.PI * this.radius ** 2;
      };
    }
    
    // 반지름이 1인 인스턴스 생성
    const circle1 = new Circle(1);
    
    // 반지름이 2인 인스턴스 생성
    const circle2 = new Circle(2);
    上記のコードがある場合、Circleジェネレータ関数は、インスタンスを作成するたびに同じ操作を実行するgetAreaメソッドを繰り返し生成し、すべてのインスタンスが同じ操作を実行するメソッドを繰り返し生成します.

    では、同じ動作をする方法で宣言を繰り返す必要がありますか?
    特定のスペースに格納し、この方法を使用すると、不要なメモリの浪費を減らすことができますか?
    これらの悩みを解決することは継承です.
    JSはプロトコルタイプに基づいてこれらの継承を実現する.

    共有メソッドを継承します。

    // 생성자 함수
    function Circle(radius) {
      this.radius = radius;
    }
    
    // 프로토타입에 getArea 메서드를 추가
    Circle.prototype.getArea = function() {
      return Math.PI * this.radius ** 2;
    };
    
    // 인스턴스 생성
    const circle1 = new Circle(1);
    const circle2 = new Circle(2);

    上図に示すように、prototypeを使用すると、Circleジェネレータ関数によって生成されたすべてのインスタンスは、親として機能するCircle.prototypeのすべてのpropertyおよびメソッドを継承します.
    このようにコードの再利用を実現することは、コードの再利用の観点から非常に有用である.
    コンストラクション関数は、作成するすべてのインスタンスがプロトコル・タイプによって共通のプロトコルまたはメソッドを管理するため、インスタンスは親としてのプロトコル・タイプの資産を共有でき、単独で実装する必要はありません.

    プロトタイプ内部スロット[prototype]


    原型をもっと深く理解しましょう.
    まず、すべてのオブジェクトに[[Prototype]]という内部スロットがあります.この内部スロットの値はプロトタイプの参照です.[[Prototype]]に格納されたプロトコルタイプは、オブジェクトの作成方法によって決定され、すなわち、オブジェクトの作成時に、オブジェクトの作成方法に基づいてプロトコルタイプが決定され、[[Prototype]]の内部スロットに格納される.
    すべてのオブジェクトにはプロトタイプがあり、すべてのプロトタイプはコンストラクション関数に関連付けられています.
    [[Prototype]]の内部スロットに直接アクセスすることはできませんが、__proto__のビジタープログラムを使用して、独自のプロトコルタイプに間接的にアクセスできます.
    さらに、プロトタイプは、独自のconstructor propertyによってコンストラクション関数にアクセスすることができ、コンストラクション関数は、独自のprototype propertyによってプロトタイプにアクセスすることができる.
    ここまでは,今後説明するプロトタイプの基本知識のみを整理した.
    次に、例を見てみましょう.

    コンストラクション関数のプロトタイプ

    // 생성자함수
    function Person(name) {
      this.name = name;
    }
    
    const me = new Person('Son');
    上記のPersonジェネレータ関数を使用してmeインスタンスを作成する場合、プロトタイプはどのように作成および管理されますか?
    画像から以下のように分かる.

    コンストラクション関数を使用したプロトタイプオブジェクトの作成


    プロトタイプとコンストラクション関数は単独では存在せず、常にペアで存在します.
    したがって、Personコンストラクタが生成されると、Person.prototypeオブジェクトも生成される.

    しかし、この生成プロセスは、単純にPersonを生成してサブ関数を生成するのではなく、プロトタイプに基づいてPersonを生成してサブ関数を生成する.

    meインスタンスの作成


    meインスタンスを作成すると、meオブジェクトのプロトタイプのconstructor propertyによってコンストラクション関数に関連付けられます.
    従って、meインスタンスは、プロトタイプPerson.prototypeconstructorおよびPerson.prototypeのpropertyおよび方法を継承し、使用することができる.

    このオブジェクトは、プロトコル・タイプによってプロトコルを参照し、プロトコル・チェーンと呼ばれるメソッドを呼び出すことができます.

    プロトタイプチェーン


    プロトタイプチェーンをよりよく理解するために、次のコードを実行します.
    me.hasOwnProperty('name'); // true
    以上で生成した構造関数PersonにはhasOwnPropertyの方法はないことは明らかであるが、hasOwnPropertyの方法はよく動作していることがわかる.
    では、hasOwnPropertyはどこに存在するのでしょうか.
    下図に示すように、Object.prototypeオブジェクトのうちhasOwnPropertyがある.
    しかし、Object.prototypeは私たちが作成したことのないオブジェクトであり、プロトタイプに存在する理由は何ですか?

    これはJSがデフォルトでコードを評価する前に、すなわち、実行時までに標準構築を含むオブジェクトを含むグローバルオブジェクトを生成し、標準構築のオブジェクトにObjectコンストラクタを提供し、Objectコンストラクタを生成すると同時にObject.prototypeオブジェクトを生成する.すべてのオブジェクトがObjectコンストラクタを使用して作成されるため、Person.prototypeオブジェクトもObject.prototypeオブジェクトである継承対象であり,Object.prototypeを含むまでのプロトタイプチェーンを形成する.

    DOMのプロトタイプ


    この文章ではDOMとは何かについては議論しませんが、内容の理解を助けるために簡単に整理します.
    まずDOMはノードオブジェクトからなるツリーデータ構造である.
    つまりDOMもオブジェクトで構成されています.
    ではDOMはどのような形で継承されているのでしょうか.input要素ノードのツリーノードを変更するとします.
    <input id="user" type="text" value="wonjae">
    const $input = document.querySelector('input');
    
    $input.setAttribute('value', 'foo');
    input要素ノードが生成される場合、ツリーノードに関する接続情報とサブノードに関する情報は当然である.
    しかし、setAttributeという方法はありません.
    これはどのようにしてメソッドにナビゲートして使用できますか?
    探索過程を下図に示す.

  • スキャンチェーンで識別子が有効かどうかを探索します.

  • 識別子が有効な場合は、オブジェクトであることを確認し、setAttributeプロトコルが存在するかどうかをプロトコルタイプチェーンで確認します.
  • input要素ノードオブジェクトには対応するpropertyがないため、prototypeチェーンを介してそのpropertyが存在するElement.prototypeオブジェクトに移動してナビゲートする.

  • メソッドを管理して呼び出します.
  • 上記の手順により、識別子はscopeチェーン内でprototypeチェーン内で検索され、input要素ノードオブジェクトのツリーノードを操作することができる.