1. プロトタイプ チェーンの継承: コンストラクター、プロトタイプ、インスタンス間の関係: 各コンストラクターにはプロトタイプ オブジェクトがあり、プロトタイプ オブジェクトにはコンストラクターへのポインターとインスタンスが含まれます。プロトタイプ オブジェクトへの内部ポインタが含まれています。プロトタイプとインスタンスの関係を確認するには、instanceof を使用します。
プロトタイプチェーン継承の欠点: プロトタイプのリテラルオーバーライドにより関係が壊れ、参照型のプロトタイプが使用され、サブタイプはスーパータイプにパラメーターを渡すことができません
function Parent(){ this.name='mike'; } function Child(){ this.age=12; } //儿子继承父亲(原型链) Child.prototype=new Parent();//Child继承Parent,通过原型形成链条 var test=new Child(); console.log(test.age); console.log(test.name);//得到被继承的属性 //孙子继续原型链继承儿子 function Brother(){ this.weight=60; } Brother.prototype=new Child();//继承原型链继承 var brother=new Brother(); console.log(brother.name);//继承了Parent和Child,弹出mike console.log(brother.age);//12 console.log(brother instanceof Child);//ture console.log(brother instanceof Parent);//ture console.log(brother instanceof Object);//ture
2. コンストラクターは継承を実装します。これは、偽オブジェクトまたはクラシック継承とも呼ばれます。
コンストラクター実装継承のデメリット: コンストラクターを借用することでプロトタイプチェーン継承の 2 つの問題は解決しますが、プロトタイプがないと再利用できないため、プロトタイプチェーン + コンストラクターを借用するパターンが必要になります。
function Parent(age){ this.name=['mike','jack','smith']; this.age=age; } function Child(age){ Parent.call(this,age);//把this指向Parent,同时还可以传递参数 } var test=new Child(21); console.log(test.age);//21 console.log(test.name); test.name.push('bill'); console.log(test.name);//mike,jack,smith,bill
3. 組み合わせの継承: プロトタイプ チェーンを使用してプロトタイプのプロパティとメソッドを継承し、コンストラクターを借用してインスタンス プロパティの継承を実現します。このように、関数の再利用はプロトタイプでメソッドを定義することによって実現され、各実装は独自の属性を持つことが保証されます。
欠点: いずれの場合も、スーパータイプ コンストラクターは 2 回呼び出されます。1 回はサブタイプ プロトタイプの作成時、1 回はサブタイプ プロトタイプの作成時、もう 1 回はサブタイプ コンストラクター内で呼び出されます。
function Parent(age){ this.name=['mike','jack','smith']; this.age=age; } Parent.prototype.run=function(){ return this.name+' are both '+this.age; } function Child(age){ Parent.call(this,age);//给超类型传参,第二次调用 } Child.prototype=new Parent();//原型链继承,第一次调用 var test1=new Child(21);//写new Parent(21)也行 console.log(test1.run());//mike,jack,smith are both 21 var test2=new Child(22); console.log(test2.age); console.log(test1.age); console.log(test2.run()); //这样可以使test1和test2分别拥有自己的属性age同时又可以有run方法
4. プロトタイプの継承: プロトタイプを使用すると、カスタム タイプを作成しなくても、既存のオブジェクトに基づいて新しいオブジェクトを作成できます。別のオブジェクトの基礎となるオブジェクトが存在する必要があります。
function object(o){ function F(){}; F.prototype=o; return new F(); } var person={ name:'nicho', friends:['shell','jim','lucy'] } var anotherPerson = object(person); anotherPerson.name = 'Greg'; anotherPerson.friends.push('Rob'); console.log(anotherPerson.friends);//["shell", "jim", "lucy", "Rob"] var yetAnotherPerson = object(person); yetAnotherPerson.name = 'Linda'; yetAnotherPerson.friends.push('Barbie'); console.log(yetAnotherPerson.friends);//["shell", "jim", "lucy", "Rob", "Barbie"] console.log(person.friends);//["shell", "jim", "lucy", "Rob", "Barbie"]
ECMAScript5 は、新しい Object.create() メソッドを通じてプロトタイプの継承を標準化します。このメソッドは、新しいオブジェクトのプロトタイプとして使用されるオブジェクトと、(オプション) 新しいオブジェクトのプロパティを定義するオブジェクトという 2 つのパラメーターを受け取ります。
var person2={ name:'nicho', friends:['shell','jim','lucy'] }; var anoP2=Object.create(person2); anoP2.name="Greg"; anoP2.friends.push('Rob'); console.log(anoP2.friends);//["shell", "jim", "lucy", "Rob"] var yetP2=Object.create(person2); yetP2.name="Linda"; yetP2.friends.push('Barbie'); console.log(yetP2.friends);//["shell", "jim", "lucy", "Rob", "Barbie"] console.log(person2.friends);//["shell", "jim", "lucy", "Rob", "Barbie"] /*以这种方式指定的任何属性都会覆盖原型对象上的同名属性。*/ var threeP=Object.create(person,{ name:{value:'red'} }); console.log(threeP.name);//red,如果threeP中无name则输出person2里的name值nicho
5. 寄生継承: この考え方は、寄生コンストラクターとファクトリ パターンに似ています。つまり、継承プロセスをカプセル化するためにのみ使用される関数を作成します。関数はオブジェクトを強化するために内部で何らかの方法で使用され、最終的には実際にすべての作業を行ったかのようにオブジェクトを返します。
function object(o){ function F(){}; F.prototype=o; return new F(); }; function createAnother(o){ var cl=object(o); cl.sayHi=function(){ console.log('hi'); } return cl; }; var person={ name:'nick', friends:['shelby','court','van'] } var anotherPerson=createAnother(person); anotherPerson.sayHi();//hi console.log(anotherPerson.name);//nick console.log(anotherPerson.friends);//["shelby", "court", "van"] /*这个例子中的代码基于 person 返回了一个新对象—— anotherPerson 。 新对象不仅具有 person 的所有属性和方法,而且还有自己的 sayHi() 方法*/
寄生結合継承: どのような状況であっても、スーパータイプ コンストラクターは 2 回呼び出されます (サブタイプ プロトタイプの作成時に 1 回、サブタイプ プロトタイプの作成時に 1 回、サブタイプ関数の作成中に 1 回)。そのため、サブタイプは終了します。スーパータイプ オブジェクトのすべてのインスタンス プロパティが含まれており、サブタイプ コンストラクターを呼び出すときにオーバーライドする必要があります。したがって、寄生的な組み合わせ継承が出現します。
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); this.age=age; } function object(o){ function F(){}; F.prototype=o; return new F(); }; /*inheritPrototype此函数第一步是创建超类型原型的一个副本。第二步是为创建的副本添加constructor属性, * 从而弥补因重写原型而失去的默认的constructor属性,第三步将新创建的对象(副本)赋值给子类型的原型*/ function inheritPrototype(subType,superType){ var prototype=object(superType.prototype);//创建对象 prototype.constructor=subType;//增强对象 subType.prototype=prototype;//指定对象 } inheritPrototype(SubType,SuperType); SubType.prototype.sayAge=function(){ console.log(this.age); } var p=new SubType('xiaoli',24); console.log(p.sayName()); console.log(p.sayAge()); console.log(p.colors)
このメソッドの利点: 親クラスの SuperType コンストラクターは 1 回だけ呼び出されるため、SubType.prototype に不要な冗長な属性が作成されることが回避されます。同時に、プロトタイプチェーンは変更されず、instanceof と isPrototypeOf() は通常どおり使用できます。