ECMAScriptは継承の実装のみをサポートし、実際、継承は主にプロトタイプチェーンに依存することで実現されます
試作チェーン
各オブジェクトとプロトタイプにはプロトタイプがあるため、オブジェクトのプロトタイプはプロトタイプオブジェクトを指し、親のプロトタイプは親の親を指します。このようなプロトタイプは相互に接続されて、プロトタイプチェーンを形成します。
基本的な考え方:プロトタイプを使用して、ある参照タイプに別の参照タイプのプロパティとメソッドを継承させます。
コンストラクター、プロトタイプ、インスタンスの関係:各コンストラクターにはプロトタイプオブジェクトがあり、プロトタイプオブジェクトにはコンストラクターへのポインターが含まれており、インスタンスにはプロトタイプオブジェクトへの内部ポインターが含まれています。
プロトタイプチェーンの基本的な概念:
プロトタイプオブジェクトを別のタイプのインスタンスと等しくします。このとき、プロトタイプオブジェクトには別のプロトタイプへのポインターが含まれ、別のプロトタイプには別のコンストラクターへのポインターも含まれます。別のプロトタイプが別のタイプのインスタンスであると仮定すると、上記の関係が依然として維持されるため、プログレッシブのレイヤーがインスタンスとプロトタイプのチェーンを形成するのに十分です。
プロトタイプチェーンを実装するための基本モデル:
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
}
fucntion SubType(){
this.subproperty = fasle;
}
//继承了superType属性和方法
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function(){
return this.Subproperty;
}
var instance = new SubType();
alert(instance.getSuperValue);//true
SubTypeはSuperTypeを継承します。継承は、SuperTypeのインスタンスを作成し、それをsubType.prototypeに割り当てることによって実現されます。
実装の本質は、プロトタイプオブジェクトを書き換えて、新しいタイプのインスタンスに置き換えることです。
例の例とコンストラクタとプロトタイプの関係
①上記のコードでは、SubTypeのデフォルトのプロトタイプを渡さず、SuperTypeのインスタンスである新しいプロトタイプを置き換えました。新しいプロトタイプには、SuperTypeのインスタンスとしてすべてのプロパティとメソッドのみが含まれ、SuperTypeのプロトタイプを指すポインターも内部にあります。
②getSuperValue()メソッドはまだSuperType.prototypeにありますが、プロパティはSubType.prototypeにあるため、propertyはインスタンスプロパティであり、getSuperValue()はプロトタイプメソッドです。SubType.prototypeがSuperTypeのインスタンスになったので、プロパティはもちろんそのインスタンスにあります。
③プロトタイプチェーンによる継承の場合、プロトタイプチェーンに沿って上向きに検索プロセスが続行されます。
④instance.getSuperValueを呼び出すと、次の3つの検索ステップが実行されます。①インスタンスの検索②SubType.prototypeの検索③SuperType.prototypeの検索
- デフォルトのプロトタイプを忘れないでください
。すべての関数のデフォルトのプロトタイプはObjectのインスタンスです。したがって、デフォルトのプロトタイプにはObject.prototypeへの内部ポインタが含まれます。理由。 - プロトタイプとインスタンスの関係
を決定する方法は2つあります。①instanceof()演算子を使用して、インスタンスとプロトタイプチェーンに現れたコンストラクターをテストすると、結果はtrueを返します。
alert(instance instanceof SuperType); // true Object、SuperType、SubTypeはすべてtrueを
返す②プロトタイプに現れたプロトタイプがプロトタイプチェーン
アラートから派生したインスタンスのプロトタイプであると言える限り、isPrototypeOf()メソッドを使用する(Object .prototype.isPrototypeOf(instance)); // true - メソッドを慎重に定義する
サブタイプは、タイプのメソッドをオーバーライドする必要がある場合や、スーパータイプにメソッドを追加する必要がある場合があります。ただし、いずれの場合でも、プロトタイプにメソッドを追加するコードは、プロトタイプ置換ステートメント
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function(){// Add method
return this.Subproperty;
}
SubTypeの後に配置する必要があります。 prototype.getSuperValue = function(){//スーパータイプメソッドを書き換えて、このメソッドを呼び出す
falseを返します
}
プロトタイプチェーンを介して継承する場合、オブジェクト文字を使用してプロトタイプメソッドを作成することはできません。これはプロトタイプチェーンを書き換えます - プロトタイプチェーンの
問題主な問題は、参照型の値を含む
プロトタイプにあり、プロトタイプによる継承を実装すると、プロトタイプは実際には別の型のインスタンスになります。その結果、元のインスタンス属性は論理的に現在のプロトタイプ属性になりました。(共有の問題)
2番目の問題は、サブタイプのインスタンスを作成するときに、スーパータイプコンストラクターにパラメーターを渡すことができないことです。
コンストラクターを借りる
①プロトタイプの参照型の値によって引き起こされる問題を解決し、コンストラクター(偽造オブジェクトまたは従来の継承)を借用する手法を使用します。
アイデア:サブタイプコンストラクター内でスーパータイプコンストラクターを呼び出します。
②関数は、特定の環境でコードを実行するオブジェクトにすぎないため、apply()およびcall()メソッドを使用して、新しく作成された(将来の)オブジェクトに対してコンストラクターを実行することもできます。
function SuperType(){
this.colors = ["red","green","black"];
}
fucntion SubType(){
SuperType.call(this);//继承SuperType
}
var instance1 = new SubType();
var instance2 = new SubType();
instance1.colors.push("blue");
alert(instance1.colors);//"red,green,black,blue"
alert(instance2.colors);//"red,green,black"
③スーパータイプのコンストラクタ「Secondary」。call()メソッドを使用して、新しく作成されたSubTypeインスタンスのコンテキストのために(実際に)SuperTypeコンストラクターを呼び出します。このようにして、SuperType()関数で定義されたすべてのオブジェクト初期化コードは、新しいSubTypeオブジェクトで実行されます。その結果、SubTypeの各インスタンスには、colors属性の独自のコピーがあります。
-
パラメーター
を渡すサブタイプコンストラクターのスーパータイプコンストラクターにパラメーターを渡すことができます。function SuperType(){ this.name = name; } fucntion SubType(){ Super.call(this,"abc");//继承SuperType,同时还传参 this.age = 29;//实例属性 } var instance = new SubType(); alert(instance.name);//"abc" alert(instance.age);//"29"
-
コンストラクターの借用の問題は、
コンストラクターの問題を回避することはできません。パターンメソッドはコンストラクターで定義されているため、関数の再利用については説明できません。
結合された継承
クラシック継承とも呼ばれ、プロトタイプチェーンとコンストラクターテクノロジーを組み合わせて両方を組み合わせた継承のモデルを指します。
アイデア:プロトタイプチェーンを使用して、プロトタイププロパティとメソッドの継承を実現し、コンストラクターを借りてインスタンスプロパティの継承を実現します。プロトタイプにメソッドを定義することで関数の再利用を実現するだけでなく、各インスタンスが独自のプロパティを持つようにします。
function SuperType(name){//定义两个属性name,colors
this.name = name;
this.colors = ["red","green","black"];
}
SuperType.prototype.sayName = function(){//SuperType原型定义一个方法
return this.name;
}
function SubType(name,age){
SuperType.call(this,name);//SubType调用SuperType时传入name参数,定义自己的属性age
this.age = age;
}
SubType.prototype = new SuperType();//SubType的实例赋值给SubType
SubType.prototype。constructor = SubType;
SubType.prototype.satAge = function(){
alert(this.age);
}
//定义方法这样一来,可以让两个不同的subType实例既分别拥有自己属性包括colors属性也可以使用相同的方法了
var instance1 = new SubType("abc",29);
instance1.colors.push("black");
alert(instance1.colors);//"red,green,blue,black"
instance1.sayName();//"abc"
instance.sayAge();//29
var instance2 = new SubType("Greg",21);
alert(instance1.colors);//"red,green,blue"
instance1.sayName();//"Greg"
instance.sayAge();//21
プロトタイプの継承
Douglas Crockfordのアイデアは、プロトタイプの助けを借りて、カスタムタイプを作成しなくても、既存のオブジェクトに基づいて新しいオブジェクトを作成できるというものです。
function object(o){
function F(){}
F.prototype = o;
return new F();
}
var person = { //另一个对象基础是person对象
name:"A";
friends:["B","C","D"];
}
var anotherperson = Object(person);
anotherperson.name = "E";
anotherperson.friends.push("F");
var yetAnotherperson = Object(person);
yetAnotherperson.name = "H";
yetAnotherperson.friends.push("I");
alert(person.friends);//"B,C,D,F,I"
オブジェクト()関数内では、まず一時コンストラクターが作成され、次に渡されたオブジェクトがこのコンストラクターのプロトタイプとして使用され、最後にこの一時タイプの新しいインスタンスが返されます。
基本的に、object()は、渡されたオブジェクトの浅いコピーを実行します。
新しいオブジェクトを返すobject()関数に渡します。新しいオブジェクトは、人をプロトタイプとして使用します。したがって、そのプロトタイプには、基本的な型の値の属性と参照型の属性が含まれています。person.friendsはpersonに属しているだけでなく、anotherPersonとyetAnotherpersonにも共有されています。personオブジェクトの2つのコピーを作成することと同じです。
プロトタイプの継承では、別のオブジェクトの基礎として使用できるオブジェクトが必要です。そのようなオブジェクトがある場合は、オブジェクト関数に渡して、特定のニーズに応じてオブジェクトを変更できます。
ECMAScript5は、Object.create()メソッドを追加してプロトタイプ継承を標準化します。2つのパラメーター:新しいオブジェクトのプロトタイプとして使用されるオブジェクトと、(オプションで)新しいオブジェクトの追加のプロパティを定義するオブジェクト。Oject()メソッドと同じ動作var anotherperson = Object(person); var anotherperson =
Object.create(person);
var yetAnotherperson = Object(person);に置き換えvar yetAnotherperson = Objectに置き換えます。作成(人);
寄生的遺伝
継承プロセスをカプセル化するためだけに使用される関数を作成します。関数は内部的になんらかの方法でオブジェクトを拡張し、最終的に、実際にすべての作業を行ったかのようにオブジェクトを返します
function createAnother(original){
var clone = Object(original);//通过调用函数创建一个新对象
clone.sayHi = function(){//以某种方式来增强这个对象
alert("Hi");
}
return clone;//返回这个对象
}
var person = {
name:"A",
friends:["B","C","D"];
}
var anotherPerson = createAnother(person);
anotherPerson.sayHi();//"Hi"
personは、新しいobject-anotherPresonを返します。新しいオブジェクトには、personのすべての属性とメソッドだけでなく、独自のsayHi()メソッドもあります。
寄生継承を使用して関数をオブジェクトに追加すると、関数を再利用できないため効率が低下します。
寄生結合遺産
組み合わせ継承の最大の問題は、どのような状況であっても、スーパータイプコンストラクターが2回呼び出されることです。1回はサブクラスプロトタイプの作成時、もう1回はサブクラスコンストラクターの内部です。
サブタイプには最終的にスーパータイプオブジェクトのすべてのインスタンス属性が含まれますが、サブタイプコンストラクターを呼び出すときにこれらの属性をオーバーライドする必要があります。
function SuperType(name){
this.name = name;
this.colors = ["red","green","black"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
}
function SubType(name,age){
SuperType.call(this,name);//第二次调用superType()在新对象上创建了实例属性name,colors这两个属性就屏蔽了原型中的两个同名属性
this.age = age;
}
SubType.prototype = new SuperType();//第一次调用superType(),得到两个属性都是superType的实例属性。
SubType.prototype。constructor = SubType;
SubType.prototype.satAge = function(){
alert(this.age);
}
このように書くと、名前と色の属性のセットが2つあり、1つはインスタンスに、もう1つはsubTypeプロトタイプに設定されます。
①寄生結合の継承、つまりコンストラクターを借りてプロパティを継承し、プロトタイプチェーンのハイブリッド形式でメソッドを継承します。
②基本的な考え方:サブタイプのプロトタイプを指定するためにスーパータイプコンストラクターを呼び出す必要はなく、必要なのはスーパータイププロトタイプのコピーだけです。
③本質:寄生継承クラスを使用してスーパータイプのプロトタイプを継承し、その結果をサブタイプのプロトタイプに割り当てます。
function inheritPrototype(subType,superType){
var prototype = Object(superType.prototype);//创建对象 创建超类型原型的副本
prototype.construcoter = subType;//增强对象,为创建的副本添加constructor属性
subType.prototype = prototype;//指定对象,为新创建的对象(副本)赋值给子类型的原型
}
④上記の例①②は置き換えられ、inheritPrototype(SubType、SuperType)になります。this
このように、SuperTypeコンストラクターを1回だけ呼び出すことで効率が向上し、SubType.prototypeに不要な追加プロパティが作成されるのを回避できます。同時に、プロトタイプチェーンは変更されないままにすることができるため、instanceofおよびisPrototypeOf()を通常どおり使用できます。