JavaScriptはどのように対象継承を実現しますか?

22805 ワード

1プロトタイプチェーン
JavaScriptのプロトタイプを利用して、他の引用タイプの属性と方法を引き継ぐことができます.
//  
function SuperType() {
    this.property = true;
}

SuperType.prototype.getSuperValue = function () {
    return this.property;
};

//  
function SubType() {
    this.subproperty = false;
}

//      
SubType.prototype = new SuperType();

SubType.prototype.getSubValue = function () {
    return this.subproperty;
};

var instance = new SubType();
console.log(instance.getSuperValue());//true
実現の本質は元のオブジェクトを書き換えることであり、新しいタイプの実例を代用することである.それらの間の関係:
プロトタイプチェーンによる継承が実現された場合、プロトタイプチェーンの終端が停止するまではプロトタイプチェーンに沿って検索されます.上記の例の検索順序は:1.検索例です.2.SubType.prototypeを検索します.3.SuperType.prototypeを検索します.
1.1標準の原型
なお、すべての参照タイプはデフォルトではObjectから継承されており、この継承もプロトタイプチェーンにより実現されている.したがって、上記の例の完全な関係図は、
1.2原型と実例の関係を確定する
例のタイプがプロトタイプチェーンに登場した場合、instance ofオペレータを使ってtrueに戻ります.
console.log(instance instanceof Object);//true
console.log(instance instanceof SuperType);//true
console.log(instance instanceof SubType);//true
同様に、isPrototypeOf()を用いて判断することもできる.
console.log(Object.prototype.isPrototypeOf(instance));//true
console.log(SuperType.prototype.isPrototypeOf(instance));//true
console.log(SubType.prototype.isPrototypeOf(instance));//true
1.3慎重に方法を定義する
サブタイプは、親タイプをやり直す方法が必要な場合があります.または親タイプにはない方法を加えて、原型に付ける方法は、必ず原型を置き換える語句の後に置くことを覚えてください.
//  
function SuperType() {
    this.property = true;
}

SuperType.prototype.getSuperValue = function () {
    return this.property;
};

//  
function SubType() {
    this.subproperty = false;
}

//      
SubType.prototype = new SuperType();

//     
SubType.prototype.getSubValue = function () {
    return this.subproperty;
};

//        
SubType.prototype.getSuperValue= function () {
    return false;
};

var instance = new SubType();
console.log(instance.getSuperValue());//false
プロトタイプチェーンによって継承が実現される場合、対象の字面量を使ってプロトタイプ方法を作成することはできません.これはプロトタイプチェーンを書き換えます.
//  
function SuperType() {
    this.property = true;
}

SuperType.prototype.getSuperValue = function () {
    return this.property;
};

//  
function SubType() {
    this.subproperty = false;
}

//      
SubType.prototype = new SuperType();

//            ,      ,          
SubType.prototype={
    getSubValue: function () {
        return this.subproperty;
    },
    someOtherMethod: function () {
        return false;
    }
};


var instance = new SubType();
console.log(instance.getSuperValue());//  
1.4プロトタイプチェーンの問題
参照タイプ値を含むプロトタイプで定義された属性はすべてのインスタンスに共有され、プロトタイプチェーンによって継承が達成されると、プロトタイプは別のタイプのインスタンスになるので、元のインスタンスで定義された属性は現在のプロトタイプ属性になります.
function SuperType() {
    this.colors = ["red", "blue", "green"];
}

function SubType() {

}

//     
SubType.prototype = new SuperType();

var instance1 = new SubType();
instance1.colors.push("black");
console.log(instance1.colors);//"red","blue","green","black"

var instance2 = new SubType();
console.log(instance2.colors);//"red","blue","green","black"
第二の問題は、サブタイプのインスタンスを作成する際に、親タイプのコンストラクタにパラメータを渡すことができないことである.
これらの問題のため、プロトタイプチェーンを単独で使うことはあまりない.
2借用構造関数
関数は特定の環境においてコードを実行するオブジェクトであるので、appy()またはcall()方法によって新たに作成されたオブジェクト上で構造関数を実行することができます.すなわち、サブタイプの構造関数の内部で親タイプの構造関数を呼び出します.
function SuperType(){
    this.colors=["red","blue","green"];
}

function SubType(){
    //     
    SuperType.call(this);
}

var instance1=new SubType();
instance1.colors.push("black");
console.log(instance1.colors);//"red","blue","green","black"

var instance2=new SubType();
console.log(instance2.colors);//"red","blue","green"
2.1リレーパラメータ
構造関数を借りる最大の利点は,サブタイプの構造関数において,超型構造関数にパラメータを伝達できることである.
function SuperType(name) {
    this.name = name;
}

function SubType() {
    //             
    SuperType.call(this, "deniro");

    //    
    this.age = 29;
}

var instance = new SubType();
console.log(instance.name);//deniro
console.log(instance.age);//29
2.2構造関数を借りる問題
その問題は前に述べたコンストラクターモードでオブジェクトを作成するように、方法はすべてコンストラクタでしか定義できず、多重関数を実現できないので、コンストラクタモードを借りるのも単独ではあまり使われない.
3グループ引継ぎ
プロトタイプチェーンを使用してプロトタイプの属性と方法の継承を実現し、次いで構造関数を用いてインスタンス属性の継承を実現する.
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.sayAge = function () {
    console.log(this.age);
};

var instance1 = new SubType("Deniro", 19);
instance1.colors.push("black");
console.log(instance1.colors);//"red","blue","green","black"
instance1.sayName();//Deniro
instance1.sayAge();//19


var instance2 = new SubType("Lily", 15);
console.log(instance2.colors);//"red","blue","green"
instance2.sayName();//Lily
instance2.sayAge();//15
組み合わせ継承方式はプロトタイプチェーンと借用構造関数方式の利点を融合させ、instance ofとisProttypeOf()も組み合わせ継承方式で作成されたオブジェクトを識別することができるので、最も一般的な継承モードである.
4原型式継承
プロトタイプによって既存のオブジェクトに新しいオブジェクトを作成することにより、カスタムタイプを作成する必要はありません.まず、このような関数を定義する必要があります.
function object(o) {
    //          
    function F() {
    }

    F.prototype = o;//                 
    return new F();//              
}

var person = {
    name: "Deniro",
    friends: ["Lily", "Jack", "Bruce"]
};

var anotherPerson = object(person);
anotherPerson.name = "Nancy";
anotherPerson.friends.push("Rob");

var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");

console.log(person.friends);//"Lily","Jack","Bruce","Rob","Barbie"
ECMAScript 5はObject.create()を使用してプロトタイプ継承を規範化しました.
パラメータを入力
必ず記入しますか
新しいオブジェクトの原型オブジェクトとして使用します.
はい、
新しいオブジェクトの属性を追加するオブジェクトを定義します.
いいえ、
一つのパラメータが入った場合、Object.create()は以前定義されたobject()と同じ挙動です.
var person = {
    name: "Deniro",
    friends: ["Lily", "Jack", "Bruce"]
};

var anotherPerson = Object.create(person);
anotherPerson.name = "Nancy";
anotherPerson.friends.push("Rob");

var yetAnotherPerson = Object.create(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");

console.log(person.friends);//"Lily","Jack","Bruce","Rob","Barbie"
Object.creat()の2番目のパラメータはObject.defineProperties()の方法の2番目のパラメータフォーマットと同じです.各属性は自分のディスクリプタで定義されています.このように定められた属性は原型オブジェクトの同名属性をカバーします.
 var person = {
    name: "Deniro",
    friends: ["Lily", "Jack", "Bruce"]
};

var anotherPerson = Object.create(person, {
    name: {
        value: "Greg"
    }
});
console.log(anotherPerson.name);//"Greg"
一つのオブジェクトだけが他のオブジェクトと似ているようにしたいなら、原型式で継承できます.ただし、参照タイプの値を含む属性はすべてのサブタイプによって共有されます.
5寄生式引継ぎ
継承プロセスをカプセル化するための関数を作成します.関数の内部では、ある方法でオブジェクトを強化し、最後にこのオブジェクトに戻ります.
function object(o) {
    function F() {
    }

    F.prototype = o;
    return new F();
}

function createAnother(original) {
    var clone = object(original);//       
    clone.sayHi = function () {//      
        console.log("hi");
    };
    return clone;//      
}

var person = {
    name: "Deniro",
    friends: ["Lily", "Jack", "Bruce"]
};

var anotherPerson = createAnother(person);
anotherPerson.sayHi();//hi
主に対象を考慮した場合には、このモードが用いられます.このモードには、例のobject()関数が必要ではなく、新しいオブジェクトに戻る関数が適用されます.
注意:寄生式継承を適用してオブジェクトに関数を追加すると、関数多重ができないため効率が低下します.
6寄生ユニット引き継ぎ
前に述べた組み合わせの継承も不足しています.それは二回の超構造関数を呼び出します.*サブタイプの原型を作る時*サブタイプの構造関数の内部にいる時
 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);//      SuperType()

    this.age = age;
}

//    
SubType.prototype = new SuperType();//      SuperType()

SubType.prototype.sayAge = function () {
    console.log(this.age);
};
SuperTypeコンストラクタを初めて呼び出した時、SubType.prototypeは二つの属性を得ます.nameとcolors.SubTypeコンストラクタを呼び出すと、再度SuperTypeコンストラクタを呼び出します.これはまた新しいオブジェクトにnameとcolorsの属性を作成します.この2つの属性は原型の中の2つの同名の属性を遮断します.
寄生結合式継承は,構造関数を用いて属性を継承し,プロトタイプ鎖によって継承する方法である.基本モードは:
function inheritPrototype(subType,superType){
    var prototype = object(superType.prototype);//            
    prototype.constructor = subType;//    ,   constructor   
    subType.prototype = prototype;//              
}
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;
}

inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function () {
    console.log(this.age);
};
この方法は組み合わせよりも効率的に継承されています.SuperTypeの構造関数を一回だけ呼び出して、SubType.prototypeに不必要な、余分な属性を作成することも避けられています.まだ正常にinstance ofとisProttypeOfを使うことができます.素敵ですよね.
以上の利点を総合して、寄生結合式継承は引用型の最も理想的な継承モデルと考えられている.