ホームページ > ウェブフロントエンド > jsチュートリアル > フロントエンド開発が知っておくべきJSプロトタイプと継承_jsオブジェクト指向

フロントエンド開発が知っておくべきJSプロトタイプと継承_jsオブジェクト指向

WBOY
リリース: 2016-05-16 18:23:48
オリジナル
753 人が閲覧しました
1. プロトタイプとコンストラクター

すべての JS 関数には、オブジェクト (プロトタイプ オブジェクトとも呼ばれる) を参照するプロトタイプ属性があります。この関数にはコンストラクターと通常の関数が含まれます。コンストラクターのプロトタイプについて詳しく説明しますが、通常の関数にもプロトタイプがあることは否定できません。たとえば、通常の関数:
コードをコピー コードは次のとおりです:

関数 F (){
alert(F.prototypeinstanceofObject) //true;


コンストラクター、つまりオブジェクトを構築します。まず、コンストラクターを通じてオブジェクトをインスタンス化するプロセスを理解しましょう。

コードをコピー コードは次のとおりです。
function A(x){
this.x =x;
}
var obj=new A(1);



obj オブジェクトをインスタンス化するには、次の 3 つの手順があります。 1. obj オブジェクトを作成します: obj=new Object();

2. obj の内部 __proto__ をそれを構築する関数 A のプロトタイプにポイントします。 obj.constructor===A.prototype.constructor (A.prototype が元の A プロトタイプを指さなくなった場合でも、これは常に true です。つまり、クラスのインスタンス オブジェクトのコンストラクター プロパティは常にこれにより、obj.constructor.prototype が A.prototype を指すようになります (obj.constructor.prototype===A.prototype、以下で説明するように、A.prototype が変更された場合、これは当てはまりません) )。 obj.constructor.prototype と内部 _proto_ は、オブジェクトをインスタンス化するときに使用されます。obj にはプロトタイプ属性がありませんが、プロトタイプ チェーンのプロトタイプ属性を取得するために __proto__ を使用できます。 . およびプロトタイプ メソッド、FireFox は、FireFox でアラートできる __proto__ を公開します (obj.__proto__); 3. これとして obj を使用して、コンストラクター A を呼び出してメンバー (つまり、オブジェクトのプロパティとオブジェクトのメソッド) を設定し、初期化します。 。

これら 3 つの手順が完了すると、obj オブジェクトはコンストラクター A との接続がなくなりました。この時点で、コンストラクター A がメンバーを追加しても、インスタンス化された obj オブジェクトには影響しなくなります。このとき、obj オブジェクトは x 属性とコンストラクター A のプロトタイプ オブジェクトのすべてのメンバーを持ちます。もちろん、この時点ではプロトタイプ オブジェクトにはメンバーがありません。

プロトタイプ オブジェクトは最初は空です。つまり、メンバー (つまり、プロトタイプ プロパティとプロトタイプ メソッド) を持ちません。次のメソッドを使用して、プロトタイプ オブジェクトに含まれるメンバーの数を確認できます。




コードをコピーします
コードは次のとおりです。 var num=0; (o in A.prototype) { alert(o);//alert はプロトタイプの属性名を出力します
num ;
}
alert("member: " num);//alert はプロトタイプの属性名を出力しますプロトタイプのすべてのメンバーの数。



ただし、プロトタイプ プロパティまたはプロトタイプ メソッドが定義されると、コンストラクターを通じてインスタンス化されたすべてのオブジェクトは、これらのプロトタイプ プロパティおよびプロトタイプ メソッドを継承します。これは内部的に行われ、_proto_ チェーンが実装されます。

例:

A.prototype.say=function(){alert("Hi")};

すべての A オブジェクトには、say メソッドがあります。すべてのオブジェクトが Say メソッドのコピーを持つのではなく、プロトタイプ オブジェクトの Say メソッドが全員に共有される唯一のコピーです。


2. プロトタイプと継承


まず、単純な継承の実装を見てみましょう。


コードをコピー
コードは次のとおりです。 function A(x){ this.x =x; function B(x,y){
this.tmpObj=A;
this.tmpObj; > y=y;



5、6、7 行目: コンストラクター A を参照する一時属性 tmpObj を作成し、B 内で実行し、実行後に削除します。 B 内で this.x=x が実行されると (this は B のオブジェクトです)、B は当然 x 属性を持ちます。 もちろん、B の x 属性と A の x 属性は独立しているため、それらは独立ではありません。厳密には継承。行 5、6、および 7 は、 call(apply) メソッドを使用したより単純な実装です。 A.call(this,x);

両方のメソッドが this を A の実行に渡します。 B のオブジェクトです。そのため、A(x) は直接使用されません。この継承方法はクラス継承です(jsにはクラスはありません。ここではコンストラクタのみを指します)。Aの構築されたオブジェクトの属性メソッドはすべて継承されますが、Aのプロトタイプオブジェクトのメンバーは継承できません。この目標を達成するには、これに基づいてプロトタイプの継承を追加する必要があります。


次の例を通じて、プロトタイプとプロトタイプが参加する完全な継承について深く理解することができます。 (この記事の核心はここです^_^)
コードをコピー コードは次のとおりです:

function A( x){
this.x = x;
}
A.prototype.a = "a";
function B(x,y){
this .y = y;
A.call(this,x);
B.prototype.b1 = function(){
アラート("b1"); >B.prototype = new A();
B.prototype.b2 = function(){
alert("b2");
B.prototype.constructor = B; >var obj = new B (1,3);


この例は、B が A を継承するものです。 7 行目 クラス継承: A.call(this.x); 前述の通り。プロトタイプの継承は 12 行目で実装されています: B.prototype = new A();

これは、B のプロトタイプが A のインスタンス オブジェクトを指すことを意味します。このインスタンス オブジェクトには、未定義の x 属性があります。値「a」の属性を持ちます。したがって、B プロトタイプにもこれら 2 つの属性があります (つまり、B と A はプロトタイプ チェーンを確立しており、B は A の下位です)。先ほどのクラス継承により、B のインスタンス オブジェクトも x 属性を持ちます。つまり、obj オブジェクトには同じ名前の x 属性が 2 つあります。このとき、プロトタイプ属性 x はインスタンス オブジェクトに譲らなければなりません。属性 x なので、 obj.x は未定義ではなく 1 になります。 13 行目ではプロトタイプ メソッド b2 も定義しているため、B プロトタイプにも b2 があります。 9行目から11行目ではプロトタイプのメソッドb1が設定されていますが、12行目の実行後、Bプロトタイプにはb1メソッドが存在しなくなり、obj.b1が未定義になっていることがわかります。 12 行目で B プロトタイプ ポインタが変更されるため、b1 を持つ元のプロトタイプ オブジェクトは破棄され、当然 b1 は存在しません。
12 行目が実行されると、B プロトタイプ (B.prototype) は A のインスタンス オブジェクトを指し、A のインスタンス オブジェクトのコンストラクターはコンストラクター A であるため、B.prototype.constructor がコンストラクター オブジェクトになります。 A. (つまり、A は B のプロトタイプを構築します)。

alert(B.prototype.constructor) は「function A(x){...}」として出てきます。同様に、obj.constructor も A コンストラクター オブジェクトです。alert(obj.constructor) が出た後は、「関数 A(x){...}」、つまり B.prototype.constructor=== になります。 obj.constructor(true) ですが、 B.prototype===obj.constructor.prototype(false) です。前者は B のプロトタイプであり、メンバー: x、a、b2 を持ち、後者は A のプロトタイプであり、メンバーがいます:この問題を解決するにはどうすればよいでしょうか? 16 行目で、B プロトタイプのコンストラクターを B コンストラクターにリダイレクトし、次に B.prototype===obj.constructor.prototype(true) となり、すべてのメンバーが x、a、b2 になります。

16 行目がない場合、obj = new B(1,3) はインスタンス化のために A コンストラクターを呼び出しますか?答えは「いいえ」です。obj.y=3 であるため、呼び出された B コンストラクターによって依然としてインスタンス化されていることがわかります。 obj.constructor===A(true) ですが、new B() の動作では、コンストラクターを通じてインスタンス オブジェクトを作成するための上記の 3 つの手順が実行されます。最初の手順は空のオブジェクトを作成することです。ステップ、obj.__proto__ === B.prototype、B.prototype には x、a、b2 のメンバーがあり、obj.constructor は B.prototype.constructor、つまりコンストラクター A を指します。 、コンストラクター B と呼ばれます。メンバーを設定および初期化するには、属性 x、y を持ちます。 16 行を追加しないことは obj のプロパティには影響しませんが、前の段落で述べたように、obj.constructor と obj.constructor.prototype には影響します。したがって、プロトタイプ継承を使用した後は、修正操作を実行する必要があります。

12行目と16行目について、簡単に説明すると、12行目はBのプロトタイプにAのプロトタイプオブジェクトのメンバーをすべて継承させるだけでなく、Bのインスタンスオブジェクトのコンストラクタのプロトタイプもプロトタイプを指すようにしています。したがって、この欠陥は 16 行目まで修正する必要があります。

終了しました。
関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート