JavaScriptのいくつかの継承方式のまとめ

4718 ワード

1、プロトタイプチェーン継承
サブタイプのプロトタイプを直接親タイプの例、すなわち「サブタイプ.prototype=new親タイプ()」に向ける方法は以下の通りである.
//      
function father(name) {
    this.name = name;
    this.colors = ['red'];
}
//      
father.prototype.sayName = function() {
    console.log(this.name);
}
//      (  )
function son(name,age) {
    this.age = age;
}
//          ,              
son.prototype = new father();

//            ,          ,               ,       (        )
son.prototype.sayAge = function() {
    console.log(this.age);
}

var tmp1 = new son('try',18);
console.log(tmp1.colors); //'red'
tmp1.sayAge();

var tmp2 = new son();
tmp2.colors.unshift('yellow'); 
console.log(tmp1.colors); //'yellow','red'
以上のコードは簡単に分かります.二つの問題があります.
  • プロトタイプチェーン方式は、すべての属性方法の共有を実現することができますが、属性・方法の共有はできません.
  • は、サブタイプのインスタンスを作成する際、パラメータを親タイプのコンストラクタに渡すことができない.実際には、すべてのオブジェクト例に影響を及ぼさないで、親タイプの構造関数にパラメータを伝達することはできないが、実際にはプロトタイプチェーンを単独で使用することは少ない.
  • 2、構造関数を借りる
    上の二つの問題を解決するために、この方法が現れました.サブタイプのコンストラクタ内で親タイプのコンストラクタを呼び出すと、関数は特定の環境でコードを実行する対象にすぎないので、appy()またはcall()の方法でコンストラクタを実行することができます.属性、方法のほかに、サブクラスのコンストラクターでパラメータを送ることもできますが、コードは多重化できません.
    function father(name) {
        this.name = name;
        this.colors = ['red'];
        this.test = function() {
            console.log('test success');
        }
    }
    father.prototype.sayName = function() {
        console.log(this.name);
    }
    
    function son(name,age) {
        //         
        father.apply(this);
        this.age = age;
    }
    
    var tmp1 = new son('try',18);
    console.log(tmp1.colors); //'red'
    tmp1.sayName(); //error!
    tmp1.test(); //OK
    
    var tmp2 = new son();
    tmp2.colors.unshift('yellow'); 
    console.log(tmp1.colors); // 'red'
    この方法にも大きな問題があります.サブクラスは、上のtestのような父親のコンストラクタの関数しか呼び出しられません.その後ろに定義されている属性の関数(上のsayNameのような)に対しては、呼び出すことができません.このため、関数多重化は説明できません.
    3、コンビネーション引継ぎ
    名前の通り、組み合わせは上の2つの方法を組み合わせて、2つの長さの継承モードを発揮します.プロトタイプチェーンを使用してプロトタイプの属性と方法の継承を実現し、構造関数を借りることによって、スタックのインスタンス属性の継承はそれぞれson.prototype = new father(); apply(this);であるが、混合モードも欠点がないわけではなく、継承方法の時に実際に親タイプの属性が継承されている.この時は引用タイプについて共有されるだけである.したがって、サブタイプのコンストラクタ内で父タイプのコンストラクタを再起動し、父タイプの属性を継承してプロトタイプに継承された属性をカバーした.二回の父の構造関数を呼び出しました.
    
    function father(name) {
        this.name = name;
        this.colors = ['red'];
        this.test = function() {
            console.log('test success');
        }
    }
    father.prototype.sayName = function() {
        console.log(this.name);
    }
    
    function son(name,age) {
        father.apply(this); //    
        this.age = age;
    }
    son.prototype = new father(); //    
    var tmp1 = new son('try',18);
    console.log(tmp1.colors); //'red'
    tmp1.sayName(); //error!
    tmp1.test(); //OK
    
    var tmp2 = new son();
    tmp2.colors.unshift('yellow'); 
    console.log(tmp1.colors); // 'red'
    4、プロトタイプ継承(寄生とこれはほぼ別個に紹介されていますが、寄生は強化対象の過程である構造関数が自分を指す)
    プロトタイプチェーンと唯一の違いは、プロトタイプ継承は実例化された親類を使わず、直接実例化された臨時複製で同じプロトタイプチェーン継承が実現されたことです.(すなわち、サブクラスのプロトタイプが親クラスコピーの例を指し、プロトタイプ共有を実現する).プロトタイプ継承は厳密な意味でのコンストラクターを使用していません.プロトタイプによって既存のオブジェクトに基づいて新しいオブジェクトを作成することができます.もちろん、このように、参照タイプ値を含む属性クロックは、それぞれの値を共有する.
    //     
    function object(o) {
      function F() {}
      F.prototype = o;
      return new F();
    }
    
    
    var father = {
        name: 'try',
        colors: ['red']
    }
    
    //ECMAScript        
    var son1 = Object.create(father);
    son1.name = 'rr';
    son1.colors.push('yellow');
    console.log(son1.colors);
    
    var son2 = Object.create(father);
    console.log(son2.colors);
    5、寄生組合式継承
    完璧な継承方式、重点掌握.寄生+借用構造は、以前に2つの親構造関数を呼び出す必要がある問題を解決した.寄生結合式継承とは,構造関数を用いて属性を継承し,プロトタイプ鎖の混成形式によって方法を継承することである.例によってサブタイプのプロトタイプを指定する必要はなく、親タイプのコンストラクタを呼び出す必要があるのは、親タイプのプロトタイプのコピーにほかならない.本質的には、寄生式で受け継がれた親タイプの原型を使って、その結果をサブタイプの原型に指定します.
    
    function object(fa) {
        //            
        function F() {}; //    fa           
        F.prototype = fa; //    
        return new F();
    }
    function inheritPrototype(son, father) {
        var prototype = object(father.prototype); //    
        prototype.constructor = son; //                
        son.prototype = prototype; //    
    }
    
    function father(name) {
        this.name = name;
        this.colors = ['red'];
    }
    father.prototype.sayName = function() {
        console.log(this.name);
    }
    function son(name,age) {
        father.call(this, name);
        this.age = age;
    }
    inheritPrototype(son,father);
    
    var tmp1 = new son('try',19);
    tmp1.colors.unshift('yellow');
    var tmp2 = new son('tt',10);
    console.log(tmp2.colors); //'red'
    tmp2.sayName(); //tt
    属性継承コードはSuperType.call(this,name);です.
    プロトタイプ引継ぎコードはinheritPrototype(son,father);です.
    「JavaScript高級プログラム設計第3版」を参照してください.