概要
JavaScriptのすべてのオブジェクトには、独自の継承チェーンがあります。つまり、各オブジェクトは別のオブジェクトを継承します。これは「プロトタイプ」オブジェクトと呼ばれます。 nullを除き、独自のプロトタイプオブジェクトはありません。
プロトタイプオブジェクトの重要性は、オブジェクトAがオブジェクトBのプロトタイプである場合、オブジェクトBがオブジェクトAのすべてのプロパティとメソッドを取得できることです。オブジェクト。getProtopofメソッドは、現在のオブジェクトのプロトタイプオブジェクトを取得するために使用されます。
var p = object.getPrototypeof(obj);
上記のコードでは、オブジェクトPはオブジェクトOBJのプロトタイプオブジェクトです。
Object.Createメソッドは、新しいオブジェクトを生成し、指定されたオブジェクトを継承するために使用されます。
var obj = object.create(p);
上記のコードでは、新しく生成されたOBJオブジェクトのプロトタイプはオブジェクトpです。
非標準の__Proto__属性(前後の2つのアンダースコア)は、特定のオブジェクトのプロトタイプオブジェクトを書き換えることができます。ただし、このプロパティをできるだけ使用しないようにする必要がありますが、Object.getPrototypeof()およびobject.setPrototypeof()を使用して、プロトタイプオブジェクトを読み書きします。
var obj = {}; var p = {}; obj .__ proto__ = p; object.getPrototypeof(obj)=== p // true上記のコードは、__Proto__属性を介してOBJオブジェクトのプロトタイプとしてPオブジェクトを設定します。
これが実用的な例です。
var a = {x:1}; var b = {__proto__:a}; bx // 1上記のコードでは、オブジェクトBはそのプロトタイプオブジェクトを__Proto__属性を介してオブジェクトとして設定するため、オブジェクトBはオブジェクトaのすべてのプロパティとメソッドを取得できます。 Bオブジェクト自体にはx属性がありませんが、JavaScriptエンジンはそのプロトタイプオブジェクトAを__proto__属性を介して見つけ、aのx属性を読み取ります。
新しいコマンドは、コンストラクターを介して新しいインスタンスオブジェクトを作成します。インスタンスオブジェクトのプロトタイプをコンストラクターのプロトタイププロパティに結合し、インスタンスオブジェクトでコンストラクターを実行します。
var o = new foo(); //はvar o = new object(); o .__ proto__ = foo.prototype; foo.call(o);
プロトタイプオブジェクトの__Proto__属性は、他のオブジェクトを指すこともでき、それによりレベルごとに「プロトタイプチェーン」を形成します。
var a = {x:1}; var b = {__proto__:a}; var c = {__proto__:b}; cx // 1プロトタイプチェーンで特定の属性を探すことは、パフォーマンスに影響を与えることに注意する必要があります。探しているプロトタイプオブジェクトのレベルが高いほど、パフォーマンスへの影響が大きくなります。存在しないプロパティを探すと、プロトタイプチェーン全体を横断します。
このアクションポインティング
これがどこに定義されていても、使用すると、プロトタイプオブジェクトではなく、常に現在のオブジェクトを指します。
var o = {a:2、m:function(b){return this.a + 1; }}; var p = object.create(o); pa = 12; pm()// 13上記のコードでは、PオブジェクトのMメソッドは、そのプロトタイプオブジェクトoから得られます。現時点では、Mメソッド内のこのオブジェクトはOを指すのではなく、p。
コンストラクターの継承
このセクションでは、1つのコンストラクターが別のコンストラクターを継承する方法について紹介します。
形状コンストラクターがあると仮定します。
function shape(){this.x = 0; this.y = 0;} shape.prototype.move = function(x、y){this.x += x; this.y += y; console.info( 'shape moved。');};長方形コンストラクターは形状を継承します。 function rectangle(){shape.call(this); //親クラスコンストラクターを呼び出す} // function rectangle(){this.base = shape; this.base();} //サブクラスは親クラスを継承します。上記のコードは、コンストラクターの継承が2つの部分に分割されていることを示しています。1つはサブクラスが親クラスのコンストラクターメソッドを呼び出し、もう1つはサブクラスのプロトタイプが親クラスのプロトタイプを指していることです。
上記のコードでは、サブクラスは親クラス全体を継承します。時には、単一の方法の継承のみが必要であり、次の記述方法を使用できる場合があります。
classb.prototype.print = function(){classa.prototype.print.call(this); //いくつかのコード}上記のコードでは、サブクラスBの印刷方法は、最初に親クラスAの印刷方法を呼び出し、次に独自のコードを展開します。これは、親クラスAの印刷方法を継承するのと同等です。
__Proto__属性
__Proto__属性は、現在のオブジェクトのプロトタイプオブジェクト、つまりコンストラクターのプロトタイプ属性を指します。
var obj = new object(); obj .__ proto__ === object.prototype // trueobj .__ proto__ === obj.constructor.prototype // true
上記のコードは、最初に、コンストラクター(オブジェクトまたはobj.constructor)のプロトタイプ属性を指す__proto__属性である新しいオブジェクトobjを作成します。したがって、2つを比較した後、trueを返します。
したがって、インスタンスオブジェクトOBJのプロトタイプオブジェクトを取得するには、3つの方法があります。
上記の3つの方法のうち、最初の2つはあまり信頼できません。最新のES6標準では、ブラウザのみが__Proto__属性を展開する必要があり、他の環境が展開されないことを規定しています。ただし、obj.constructor.prototypeは、プロトタイプオブジェクトを手動で変更すると失敗する可能性があります。
var p = function(){}; var p = new p(); var c = function(){}; c.prototype = p; var c = new c(); constructor.prototype === p // false上記のコードでは、CコンストラクターのプロトタイプオブジェクトがPに変更され、その結果、C.Constructor.Prototypeが歪んでいます。したがって、プロトタイプオブジェクトを変更する場合、コンストラクター属性を同時に設定する必要があります。
C.Prototype = P; C.Prototype.Constructor = C; C.Constructor.Prototype === P // True
したがって、3番目のobject.getPrototypeofメソッドを使用してプロトタイプオブジェクトを取得することをお勧めします。この方法の使用は次のとおりです。
var o = new object(); object.getPrototypeof(o)=== object.prototype // true
object.getProtopeofメソッドを使用して、ブラウザが古いブラウザではサポートされていない__Proto__属性をサポートしているかどうかを確認できます。
object.getPrototypeof({__proto__:null})=== null上記のコードは、オブジェクトの__Proto__属性をNULLに設定し、Object.GetProtopeOfメソッドを使用して、このオブジェクトのプロトタイプを取得して、NULLに等しいかどうかを判断します。現在の環境が__Proto__属性をサポートしている場合、2つの比較結果が真でなければなりません。
__Proto__属性を使用すると、インスタンスオブジェクトのプロトタイプを簡単に設定できます。マシン、車両、車の3つのオブジェクトがあると仮定します。マシンは車両のプロトタイプであり、車両は車のプロトタイプであり、2行のコードで設定できます。
車両.__ Proto__ = Machine; car .__ proto__ = beil;
以下は例です。プロトタイプオブジェクトで定義されているプロパティは、それぞれ__Proto__属性とconstructor.prototype属性を使用して読み取られます。
array.prototype.p = 'abc'; var a = new array(); a .__ proto __。p // abca.constructor.prototype.p // abc
明らかに、__Proto__はもう少し簡潔に見えます。
インスタンスオブジェクトがコンストラクターを介して生成されると、インスタンスオブジェクトの__Proto__属性は、コンストラクターのプロトタイプオブジェクトを自動的に指します。
var f = function(){}; var a = {}; f.prototype = a; var o = new f(); o .__ proto__ === a // true属性の継承
属性には2つのタイプがあります。 1つはオブジェクト自体のネイティブ属性であり、もう1つはプロトタイプから継承された継承された属性です。
オブジェクトのネイティブプロパティ
オブジェクト自体のすべてのプロパティは、object.getownPropertyNamesメソッドを使用して取得できます。
object.getownPropertyNames(日付)// ["parse"、 "arguments"、 "utc"、 "caller"、 "name"、 "prototype"、 "now"、 "length"]]
オブジェクト自体のプロパティの中で、一部は列挙可能(列挙可能)ですが、他のものは列挙できません。列挙できるプロパティのみを取得するには、Object.keysメソッドを使用します。
object.keys(date)// [] hasownproperty()
HasownPropertyメソッドは、ブール値を返して、特定のプロパティがオブジェクト自体またはプロトタイプチェーンで定義されているかどうかを判断します。
date.hasownproperty( 'length')// truedate.hasownproperty( 'tostring')// false
HasownPropertyメソッドは、オブジェクトプロパティを処理するときにプロトタイプチェーンを通過しないJavaScriptの唯一の方法です。
オブジェクトの継承プロパティ
Object.Createメソッドで作成されたオブジェクトは、すべてのプロトタイプオブジェクトのプロパティを継承します。
var proto = {p1:123}; var o = object.create(proto); o.p1 // 123o.hasownproperty( "p1")// falseすべての属性を取得します
オブジェクトが特定のプロパティを持っているかどうかを判断するには(独自のプロパティであろうと継承されているかどうか)、in operatorを使用します。
日付の「長さ」// true "tostring" in date // true
オブジェクトのすべての列挙可能なプロパティを取得します(独自であろうと継承されているかどうか)、for-inループを使用できます。
var o1 = {p1:123}; var o2 = object.create(o1、{p2:{value: "abc"、列挙:true}}); for(p in o2){console.info(p);} // p2 // p1for ... in loopでオブジェクトのプロパティを取得するために、HasownPropertyメソッドを使用して判断できます。
for(object in objectのvar name){if(object.hasownproperty(name)){ / * loop code * /}}}オブジェクトのすべてのプロパティを取得するには(オブジェクトが独自であろうと継承されているか、列挙可能かどうか)、次の関数を使用できます。
function enternitedpropertynames(obj){var props = {}; while(obj){object.getownPropertynames(obj).foreach(function(p){props [p] = true;}); obj = object.getPrototypeof(obj); } return object.getownPropertyNames(Props);}使用法は次のとおりです。
相続PropertyNames(date)// ["Caller"、 "Constructor"、 "tostring"、 "utc"、 "call"、 "parse"、 "prototype"、 "__ definesetter__"、 "__ lookupsetter__"、 "長さ]、「arguments"、 "bind"、 " 「PropertyIsEnumerable」、「ValueOf」、「Apply」、「__DefineGetter__」、「name」、「now」、「hasownProperty "]]]
オブジェクトのコピー
オブジェクトをコピーしたい場合は、次の2つのことを行う必要があります。
コピーされたオブジェクトが元のオブジェクトと同じプロトタイプオブジェクトを持っていることを確認してください。
コピーされたオブジェクトが元のオブジェクトと同じプロパティを持っていることを確認してください。
以下は、上記の2つのポイントに基づいて記述されたオブジェクトをコピーする機能です。
関数copyObject(orig){var copy = object.create(object.getPrototypeof(orig)); copyownPropertiesfrom(copy、orig); return copy;} function copyownPropertiesfrom(ターゲット、ソース){object .getownpropertynames(source).foreach(function(propkey){var desc = object.getownpropertydescriptor(source、propkey); object.defineproperty(ターゲット、プロップキー、desc);});ターゲットを返す;}複数の継承
JavaScriptは複数の継承関数を提供しません。つまり、1つのオブジェクトが同時に複数のオブジェクトを継承することを許可しません。ただし、この機能は回避策を通じて実現できます。
関数m1(prop){this.hello = prop;}関数m2(prop){this.world = prop;} function s(p1、p2){this.base1 = m1; this.base1(p1); this.base2 = m2; this.base2(p2);} s.prototype = new M1(); var s = new S(111、222); S.hello // 111s.world // 222上記のコードでは、サブクラスSは親クラスM1とM2の両方を継承します。もちろん、継承チェーンの観点から見ると、Sには親クラスM1が1つしかありませんが、Sのインスタンスの場合、M1とM2のコンストラクターが同時に実行されるため、これら2つのクラスの方法を同時に継承します。