Javascriptの対象継承方法


多くのOO言語は2つの継承方式をサポートしています.
  • インターフェース継承:継承方法のみ署名
  • 継承を実現する:実際の方法を継承する.
  • 関数に署名がないため、ECMAScriptではインターフェース継承ができません.ECMAScriptは継承のみのサポートです.
    プロトタイプチェーン引継ぎ
    プロトタイプチェーンはJavascriptの継承を実現する主な方法です.
    function SuperType(){
        this.property = true;
    }
    SuperType.prototype.getSuperValue = function(){
        return this.property;
    }
    function SubType(){
        this.subproperty = false;
    }
    //  SuperType
    SubType.prototype = new SuperType();
    SubType.prototype.getSubValue = function(){
        return this.subproperty;
    }
    var instance = new SubType();
    console.log(instance.getSuperValue())//true
    
    //instanceof                      
    console.log(instance instanceof object) //true
    console.log(instance instanceof SuperType) //true
    console.log(instance instanceof SubType) //true
    
    console.log(Object.prototype.isPrototypeof(instance)) //true
    console.log(SuperType.prototype.isPrototypeof(instance)) //true
    console.log(SubType.prototype.isPrototypeof(instance)) //true
    
    実際には単独でプロトタイプチェーンを使うことが少ないです.
    注意:
  • instance.co nstructureは現在SuperType
  • を指しています.
  • instance.toStringは現在Object.prototype
  • を指しています.
  • SuperTypeの参照値の種類は全てのSubTypeで共有されます.
  • SubTypeの例を作成すると、SuperTypeの構造関数にパラメータを渡すことができません.
    誤りやすい点
  • SubType、SuperTypeのプロトタイプ方法を追加するコードはプロトタイプを置換した後の文に置く.SubTypeを追加したプロトタイプは無効になります.プロトタイプのオブジェクトが入れ替わったからです.
  • は、文字通りSubTypeの原型オブジェクトを作成することができません.元のモデルに直接値を付けたため、字面量のオブジェクトがSubTypeの原型に置き換えられ、原型チェーンが壊れました.
  • 構造関数の継承を借りる
    Javascriptプロトタイプチェーン継承における参照値の種類が共有されている問題を解決しました.
    function SuperType(){
        this.colors=["red","blue","green"];
    }
    function SubType(){
        SuperType.call(this);
    }
    var instance1 = new SubType();
    instance1.colors.push("black");
    alert(instance1.colors);//"red,blue,green,black"
    
    var instance2 = new SubType();
    alert(instance2.colors);//"red,blue,green"
    call(this)またはapply(this)を介してSubTypeの例示的な環境でSuperTypeの構造関数を呼び出したので、SubTypeオブジェクト上でSuperTypeのオブジェクト初期化コードを実行し、各SubTypeはそれぞれ独自のColors属性を持っています.
    優勢
  • は、サブ構造関数において超構造関数にパラメータを伝達することができる
  • .
    問題
  • は、方法がすべて構造関数で定義されているため、関数多重が実現できず、各オブジェクトが方法を再定義した.
  • は、いずれも2回の超構造関数を呼び出します.1回はサブタイプのプロトタイプを作成する時、もう1回はサブタイプのコンストラクタの中にいます.
  • 注意
  • SuperType構造関数がサブクラス属性を書き換えないようにするためには、SuperTypeの構造関数を呼び出した後、サブクラス自体の属性を追加する必要があります.
  • グループ引継ぎ
    プロトタイプチェーンと借用構造関数を一つのブロックに結合して、両者の長い継承モードを発揮します.
  • プロトタイプチェーンは、属性および方法の多重化を実現する.
  • は、構造関数を用いて、インスタンス属性の継承を実現する.
  • function SuperType(name){
        this.name = name;
        this.colors = ["red", "blue", "green"];
    }
    SuperType.prototype.sayName = function(){
        console.log(this.name);
    };
    function SubType(name, age){
        //    
        SuperType.call(this, name);
        this.age = age;
    }
    //    
    SubType.prototype = new SuperType();
    SubType.prototype.constructor = SubType;
    SubType.prototype.sayAge = function(){
        console.log(this.age);
    };
    var instance1 = new SubType("Nicholas", 29);
    instance1.colors.push("black");
    console.log(instance1.colors); //"red,blue,green,black"
    instance1.sayName(); //"Nicholas";
    
    instance1.sayAge(); //29
    var instance2 = new SubType("Greg", 27);
    console.log(instance2.colors); //"red,blue,green"
    instance2.sayName(); //"Greg";
    instance2.sayAge(); //27
    プロトタイプ継承
    プロトタイプ継承は厳密な意味での構造関数を使用していない.は、プロトタイプによって既存のオブジェクトに基づいて新しいオブジェクトを作成することができます.したがって、カスタムタイプを作成する必要はありません.
    function object(o){
        function F(){}
        F.prototype = o;
        return new F();
    }
    object()関数の内部では、まず一時的なコンストラクタを作成し、その後、このコンストラクタのプロトタイプとして導入されたオブジェクトを最後にこの一時的なタイプの新しい例を返します.本質的には、object()は、その中に入ってきたオブジェクトに対して浅い複製を実行した.ECMAScript 5はObject.create()を追加することによりプロトタイプ継承を規範化した.この方法は2つのパラメータを受信します.
  • 新しいオブジェクトのプロトタイプとして使用されるオブジェクトおよび(オプション)
  • 新規オブジェクトの追加属性を定義するオブジェクト.
  • 一つのパラメータが入ってくる場合、Object.create()object()方法と同じ挙動をする.Object.create()方法の第2のパラメータは、Object.defineProperties()方法の第2のパラメータフォーマットと同じである.各属性は、自分のディスクリプタによって定義される.このように指定した属性はいずれも原型オブジェクト上の同名属性をカバーします.大勢の人を動員して構造関数を作成する必要はなく、一つのオブジェクトを他のオブジェクトと同じように維持したい場合、原型式継承は完全に適任です.
    寄生式引継ぎ
    オブジェクトを強化するために内部で機能を実装するためにのみ使用される関数を作成します.最後に、本当にすべての作業をしたようにオブジェクトに戻ります.
    function createAnother(original){
        //             ,                  
        var clone = object(original); 
            clone.sayHi = function(){ //            
            alert("hi");
        };
        return clone; //      
    }
    var person = {
        name: "Nicholas",
        friends: ["Shelby", "Court", "Van"]
    };
    var anotherPerson = createAnother(person);
    anotherPerson.sayHi(); //"hi"
    問題
  • は、関数多重ができず、効率を低減する
  • .
    寄生ユニット引き継ぎ
    SuperTypeの構造関数を2回呼び出したので、SubTypeは2組のSuperTypeの属性を持っています.一組は実例において、SubTypeの原型にあります.寄生結合式継承は構造関数を用いて属性を継承し,プロトタイプ鎖の混成形式により方法を継承した.基本的な考え方:サブタイプのプロトタイプを指定するために超タイプのコンストラクタを呼び出す必要はない.私たちが必要なのは、超タイプのプロトタイプのコピーにほかならない.本質:寄生式継承で超タイプの原型を継承し、結果をサブタイプの原型に指定します.
    function inheritPrototype(subType, superType){
        var prototype = object(superType.prototype); //    
        prototype.constructor = subType; //    
        subType.prototype = prototype; //    
    }
    
    function SuperType(name){
        this.name = name;
        this.colors = ["red", "blue", "green"];
    }
    SuperType.prototype.sayName = function(){
        alert(this.name);
    };
    function SubType(name, age){
        SuperType.call(this, name);
        this.age = age;
    }
    inheritPrototype(SubType, SuperType);
    SubType.prototype.sayAge = function(){
        alert(this.age);
    };
    優勢
  • 高効率:SuperType構造関数を一回だけ呼び出したので、SubType.prototype上に不必要な、余分な属性を作成することを避けました.
  • プロトタイプチェーンはまだ不変です.そのため、instance ofとisProttypeOf()を正常に使うことができます.
  • 寄生結合式継承は、引用タイプの最も理想的な継承モデルである.
  • YUIのYAHOO.lang.exted()方法は寄生グループの継承を採用しています.このようなモードは初めて応用が非常に広いJavaScriptライブラリに登場しました.
  • nodeの中のutil.inheits継承
    寄生結合継承は寄生結合継承におけるinheritPrototypeの機能と一致しているので、サブクラス間で参照タイプの値属性を共有することが望まれない場合には、さらに、借用構造関数の継承を組み合わせる必要がある.
    exports.inherits = function(ctor,superCtor){
        ctor.super_ = superCtor;
        ctor.prototype = Object.create(superCtor.prototype,{
            constructor:{
                value:ctor,
                enumerable:false,
                writable:true,
                configurable:true
            }
        };
    };