JavaScript継承の概要


プロトタイプチェーン
インスタンスのプロパティを読み込むと、見つからないとオブジェクトに関連付けられたプロトタイプのプロパティが検索され、まだ見つからない場合は、プロトタイプのプロトタイプが最上位まで検索されます.プロトタイプオブジェクトを別のタイプのインスタンスに向けると...おもしろいことが起こった.Personprototype=animal 2上記のゲームルールの有効化に鑑みて、Person構造のインスタンスperson 1の属性を引用しようとすると:1).まずinstance 1の内部属性で探します.2).続いてinstance 1._proto__(constructor 1.prototype)で探し、constructor 1.prototypeは実際にはanimal 2であり、すなわちanimal 2でこの属性p 1を探す.3).もしanimal 2にまだないならば、この时プログラムはがっかりしないで、それはanimal 2._に続くことができますproto__(Animal.prototype)で...Objectのプロトタイプオブジェクトまで
検索トラック:person 1->animal 2->Animal.prototype-->Object.prototype
この探索の軌跡は、長い鎖のような形をしており、prototypeがこのゲームルールでリンクとして機能するため、このような例とプロトタイプのチェーンをプロトタイプチェーンと呼ぶ.
JavaScript継承
継承はレプリケーション操作を意味しますが、JavaScriptのデフォルトではオブジェクトのプロパティはレプリケーションされません.逆に、JavaScriptは2つのオブジェクトの間に1つの関連付けを作成するだけです.これにより、1つのオブジェクトが別のオブジェクトのプロパティと関数にアクセスできるようになります.したがって、継承というよりも、依頼の言い方が正確になります.
——『君の知らないJavaScript』
プロトタイプチェーンベース
他のほとんどの言語とは異なり、JavaScriptはクラスベースではなくプロトタイプベースのオブジェクトシステムです.プロトタイプベースのオブジェクト向け設計方法は全部で3種類あります.
  • パッチ継承:属性を1つのオブジェクトから別のオブジェクトに直接コピーするモードです.コピーされたプロトタイプは通常mixinsと呼ばれます.ES 6はこのモードに便利なツールObjectを提供した.assign().ES 6以前には、一般的にUnderscore/LOdashが提供する.extend()またはjQueryの$.extend()を実装します.上のオブジェクトの組み合わせの例では,接合継承の方式を採用している.
  • プロトタイプエージェント:JavaScriptでは、オブジェクトにプロキシと呼ばれるプロトタイプへの参照が含まれる場合があります.アトリビュートが現在のオブジェクトに存在しない場合は、プロキシプロトタイプが検索されます.エージェントプロトタイプ自体にも独自のエージェントプロトタイプがあります.これにより、属性が見つかるまで、またはルートエージェントObjectが見つかるまで、エージェントチェーンに沿って上を検索するプロトタイプチェーンが形成される.prototypeまで.プロトタイプは、newキーワードを用いるインスタンスおよびConstructorを作成する.prototypeは前後に継承チェーンに接続されています.もちろん、Objectも使用できる.create()は、同じ目的を達成したり、パッチ継承と混用したりすることで、複数のプロトタイプを単一のエージェントに簡略化したり、オブジェクトインスタンスの作成後も拡張を続けることができます.
  • 関数継承:JavaScriptでは、任意の関数を使用してオブジェクトを作成できます.関数がコンストラクション関数でもclassでもない場合は、ファクトリ関数と呼ばれます.関数継承の動作原理は、ファクトリ関数によってオブジェクトを作成し、そのオブジェクトに直接属性を追加することで、オブジェクトを拡張します(接合継承を使用します).関数継承の概念は最初にダグラス・クロークフォードによって提案されたが,この継承方式はJavaScriptにすでに存在している.

  • コンストラクション関数による継承(クラシック継承)
     function Parent1() {
       this.name = 'parent1';
     }
     
     Parent1.prototype.say = function () {}
     
     function Child1() {
       Parent1.call(this);
       this.type = 'child';
     }
    
     console.log(new Child1);
    

    これは主にcallを借りてthisの指向を変更し,callを介してParentを呼び出し,このときParentのthisはChild 1を指す.印刷結果からChildにはsayメソッドがないため、親クラスのインスタンス属性とメソッドのみを継承し、プロトタイプ属性/メソッドを継承できないという欠点がある.注意constructorプロパティ、new操作は「一時オブジェクトがどの関数で作成されたか」を記録するため、「Child.prototype」にconstructorプロパティを追加しておきます.
    プロトタイプチェーンによる継承
    function Parent2() {
      this.name = 'parent2';
      this.play = [1, 2, 3];
    }
    
    function Child2() {
      this.type = 'child2';
    }
    Child2.prototype = new Parent2();
    
    console.log(new Child2);
    
    

    説明すると、属性を共有するにはオブジェクトが必要であることがわかります.proto__ = 父の相手prototypeですが、実際には直接操作できません.proto__,この時newを借りてやることができるのでChild 2.prototype = new Parent2(); <=> Child2.prototype.__proto__ = Parent2.prototype; これによりnewという文法糖を用いることで,プロトタイプ鎖継承を実現できる.欠点:s 1を与える.Playに新しい値が追加され、s 2も変更されました.だからこれはプロトタイプチェーン継承の欠点で、原因はs 1._pro__ とs 2._pro__同じアドレスである親Child 2へのprototype.
    グループ継承
    プロトタイプチェーンと構造関数を結合し,両者の長さを発揮する継承モードである.プロトタイプチェーンを用いてプロトタイプ属性とメソッドの継承を実現し,構造関数を借りてインスタンス属性の継承を実現することを構想する.これにより,プロトタイプ上でメソッドを定義することで関数多重化を実現し,各インスタンスに独自の属性があることを保証できる.
    初級版
    function Super(name){
        this.name = name;
        this.colors = ["red", "blue", "green"];
    }
    
    Super.prototype.sayName = function (){
        alert(this.name);
    };
    
    function Sub(name, age){
        Super.call(this, name);    //   Super    (     Sup    )
        this.age = age;
    }
    
    //    Super         (     Sup    )           ,         ,      
    Sub.prototype = new Super();    
    
    Sub.prototype.constructor = Sub;// 
    Sub.prototype.sayAge = function (){
        alert(this.age);
    };
    
    var instance1 = new Sub("Luke", 18);
    instance1.colors.push("black");
    alert(instance1.colors);    //"red, blue, green, black"
    instance1.sayName();    //"Luke"
    instance1.sayAge()    //18
    
    var instance2 = new Sub("Jack", 20);
    alert(instance2.colors);    //"red, blue, green"
    instance2.sayName();    //"Jack"
    instance2.sayAge()    //20

    最適化された組合せ継承
    function Super(name){
        this.name = name;
        this.colors = ["red", "blue", "green"];
    }
    
    Super.prototype.sayName = function (){
        alert(this.name);
    };
    
    function Sub(name, age){
        Super.call(this, name);    //   Super   
        this.age = age;
    }
    
    function F(){
    }
    F.prototype = Super.prototype; 
    Sub.prototype = new F();    //    Super        
    
    Sub.prototype.constructor = Sub;
    Sub.prototype.sayAge = function (){
        alert(this.age);
    };
    
    var instance1 = new Sub("Luke", 18);
    console.log(instance1 )
    instance1.colors.push("black");
    alert(instance1.colors);    //"red, blue, green, black"
    instance1.sayName();    //"Luke"
    instance1.sayAge()    //18
    
    var instance2 = new Sub("Jack", 20);
    alert(instance2.colors);    //"red, blue, green"
    instance2.sayName();    //"Jack"
    instance2.sayAge()    //20
    
    

    疑問
    どうしてそう書くの?
    function F(){
    }
    F.prototype = Super.prototype; 
    Sub.prototype = new F();    //    Super        

    ではなく
    Sub.prototype = Super.prototype; 

    次の方法では、オブジェクトが直接そのサブクラスによってインスタンス化されるか、親によってインスタンス化されるかを区別することはできません.次は最初の方法で判断できません
    instance1 instanceof Sub//true
    instance1 instanceof Super//true
    

    オブジェクトがクラスであるかどうかを判断する方法もあります.それはconstructorで、コンソールで以下の内容を印刷しても見分けられません.
    プロトタイプ継承
    プロトタイプにより、既存のオブジェクトに基づいて新しいオブジェクトを作成することができるとともに、object()関数の内部にカスタムタイプを作成する必要はなく、一時的なコンストラクション関数を作成してから、入力オブジェクトをこのコンストラクション関数のプロトタイプとして、最後にこのリアルタイムタイプの新しいインスタンスを返す.
    function object(o){
        function F(){}
        F.prototype = o;//  F   ,       o,        o
        return new F();//  F     
    }
    var person = {
        friends : ["Van","Louis","Nick"]
    };
    var anotherPerson = object(person);
    anotherPerson.friends.push("Rob");
    var yetAnotherPerson = object(person);
    yetAnotherPerson.friends.push("Style");
    alert(person.friends);//"Van,Louis,Nick,Rob,Style"
    

    本質的にobject()は、その中に入るオブジェクトに対して浅いコピーを実行する.使用するサブクラスは、転送されたpersonオブジェクトを指します.
    object.create()メソッドは上のプロトタイプ継承を規範化した.前の文章にはこの方法の詳細な説明がある.
    var person = {
        friends : ["Van","Louis","Nick"]
    };
    var anotherPerson = Object.create(person);
    anotherPerson.friends.push("Rob");
    var yetAnotherPerson = Object.create(person);
    yetAnotherPerson.friends.push("Style");
    alert(person.friends);//"Van,Louis,Nick,Rob,Style"
    console.log(anotherPerson)

    欠点:
    プロトタイプチェーンは、複数のインスタンスの参照タイプ属性が同じを指し、改ざんの可能性があります.パラメータを渡すことができません
    スプリアス継承
    コア:プロトタイプ継承に基づいて、オブジェクトを強化し、コンストラクション関数に戻る主な役割は、コンストラクション関数に属性とメソッドを追加し、関数を強化することです.
    function createAnother(original){
      var clone = object(original); //      object()          ,object              
      clone.sayHi = function(){  //           
        alert("hi");
      };
      return clone; //       
    }
    
    var person = {
      name: "Nicholas",
      friends: ["Shelby", "Court", "Van"]
    };
    var anotherPerson = createAnother(person);
    anotherPerson.sayHi(); //"hi"

    欠点(同プロトタイプ継承):プロトタイプチェーンが複数のインスタンスを継承する参照タイプ属性は同じを指し、改ざんの可能性がある.パラメータを渡すことができません