javaScriptで継承を実現する6つの方法


総括:とても経典的な問題、総括します.参照リンク:https://github.com/mqyqingfeng/Blog/issues/16
1.プロトタイプチェーン引継ぎ.
構造関数を構築することにより,構造関数のプロトタイプチェーンに属性と方法を付加してその機能を拡張した.new構造関数の実用化により,継承を実現した.
function Father(){
   this.name="dad name"
}

funciton Son(){
   this.age=18;
}

Son.prototype=new Father();
var test=new Son();
test.name  //"dad name"
test.age  //18
上記のコードを通して、私たちは異なる例のために異なるnameを割り当てることができません.すべてのインスタンスオブジェクトは一つのnameしか共有できません.
2.構造関数を借りて継承を実現する
コンストラクタを作成して、コンストラクタにcall,bind,applyを使って継承を実現します.
function Father(){
  this.name="dad"
}
function Son(){
   Father.call(this);
}
var test=new Son();
test.name;
まず、apply方法の運用を知っておきたいのですが、関数の作用領域を変更することができますので、上記の例では、Sonサブクラスでこの方法を呼び出します.つまり、Sonサブクラスの変数を親クラスで一回実行します.このように、親クラスの共有属性と方法があります.しかし、構造関数の継承にも欠陥があります.つまり、私たちは親の共有方法、すなわちプロトタイプprototypeによって結合された方法を得ることができません.
3.コンビネーション引継ぎ
プロトタイプチェーンの継承と借用構造関数の継承の2つの方法の組み合わせです.このようにして、両方の長所を借りて、短所を避けることができます.
//        
function Animal(color) {    
    this.name = 'animal';    
    this.type = ['pig','cat'];    
    this.color = color;   
}    
//         
Animal.prototype.greet = function(sound) {    
    console.log(sound);   
}     
//        
function Dog(color) { 
    //           
    Animal.apply(this, arguments);   
}   
//     
Dog.prototype = new Animal();   
var dog = new Dog('  ');   
dog.type.push('dog');   
console.log(dog.color); // "  "
console.log(dog.type);  // ["pig", "cat", "dog"]

var dog2 = new Dog('  ');  
console.log(dog2.type); // ["pig", "cat"]
console.log(dog2.color);  // "  "
dog.greet('  ');  // "  "
上記の例では、サブクラスの構造関数で父クラスの構造関数を実行し、サブタイプのプロトタイプでは父類を実例化しました.これは組み合わせで継承されています.クラスの継承と構造関数継承の利点を総合して、欠陥を除去しているところが見られます.おそらく、あなたは奇妙なことがありますが、なぜ組み合わせ式の継承はクラスの引用欠陥を取り除くことができますか?これは によって決定されたものです.JavaScriptエンジンは、オブジェクトの属性にアクセスする際に、まず対象自身の中で検索します.見つけられなかったら、プロトタイプチェーンの中で検索します.見つけたら、値を返します.プロトタイプチェーン全体にこの属性が見つからなかったら、undefinedに戻ります.つまり、私たちが訪問した参照タイプ(上のタイプなど)は、実はapplyを介してサブクラスにコピーされているので、共有は発生しません.この組み合わせの継承も小さな欠陥であり,それは2回の父親類の構造関数を呼び出したことである.
4.原型式継承
function createObj(o) {
    function F(){}
    F.prototype = o;
    return new F();
}
ES 5 Object.creatのシミュレーションが実現し、導入されたオブジェクトを作成の対象とする原型です.欠点は、参照タイプを含む属性値が常に対応する値を共有することであり、これはプロトタイプチェーン継承と同じである.
var person = {
    name: 'kevin',
    friends: ['daisy', 'kelly']
}

var person1 = createObj(person);
var person2 = createObj(person);

person1.name = 'person1';
console.log(person2.name); // kevin

person1.firends.push('taylor');
console.log(person2.friends); // ["daisy", "kelly", "taylor"]
person1.nameの値が修正され、person2.nameの値が変更されていないのは、person1person2に独立したname値があるからではなく、person1.name = 'person1'にname値が追加されたからであり、原型上のname値が修正されたからではない.
5.寄生式継承
エンハンスメントオブジェクトを内部で何らかの形で作り、最後にオブジェクトを返します.
function createObj (o) {
    var clone = Object.create(o);
    clone.sayName = function () {
        console.log('hi');
    }
    return clone;
}
短所:構造関数モードを借りるのと同じで、オブジェクトを作成するたびに一つの方法を作成します.
6.寄生結合式継承
皆さんが読みやすいように、ここでコンボコードを繰り返します.
function Parent (name) {
    this.name = name;
    this.colors = ['red', 'blue', 'green'];
}
Parent.prototype.getName = function () {
    console.log(this.name)
}
function Child (name, age) {
    Parent.call(this, name);
    this.age = age;
}
Child.prototype = new Parent();
var child1 = new Child('kevin', '18');
console.log(child1)
組み合わせ継承の最大の欠点は,2回の父構造関数を呼び出すことである.
一回はサブタイプのインスタンスの原型を設定する時です.
Child.prototype = new Parent();
サブタイプのインスタンスを作成する時:
var child1 = new Child('kevin', '18');
newのシミュレーションを思い出してみます.実はこの文で、私達は実行します.
Parent.call(this, name);
ここでは、私たちはまたPartentコンストラクターを呼び出します.
したがって、この例では、child 1オブジェクトを印刷すると、Child.prototypeとchild 1の属性はperson1であり、属性値はcolorsであることが分かります.
じゃ、私達はどうやって改善して、今回の繰り返しの呼び出しを避けるべきですか?
もし私たちがChild.prototype=new Part()を使わずに、間接的にChild.prototypeをPartent.prototypeに訪問させたらどうですか?
どのように実現しますか?
function Parent (name) {
    this.name = name;
    this.colors = ['red', 'blue', 'green'];
}
Parent.prototype.getName = function () {
    console.log(this.name)
}
function Child (name, age) {
    Parent.call(this, name);
    this.age = age;
}
//      
var F = function () {};
F.prototype = Parent.prototype;
Child.prototype = new F();
var child1 = new Child('kevin', '18');
console.log(child1);
最後にこの継承方法をカプセル化します.
function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
}
function prototype(child, parent) {
    var prototype = object(parent.prototype);
    prototype.constructor = child;
    child.prototype = prototype;
}
//         :
prototype(Child, Parent);
「JavaScript高級プログラム設計」の寄生ポートフォリオの継承に対する称賛は以下の通りである.
このような方式の高効率化は、一度だけPartent構造関数を呼び出し、従ってPartent.prototype上に不必要な、余分な属性を作成することを回避する.それと同時に、プロトタイプチェーンはまだ変わらないです.そのため、instance ofとisProttypeOfを正常に使うことができます.開発者は寄生結合式継承が引用型の最も理想的な継承モデルと考えられている.