JavaScriptの原型と継承


一.原型と構造関数
Jsのすべての関数にはプロトタイプの属性があります.この属性はオブジェクト、すなわちプロトタイプのオブジェクト、またはプロトタイプと呼ばれます.この関数は構造関数と一般関数を含み,より多くの構造関数のプロトタイプを説明したが,一般関数にもプロトタイプがあることは否定できなかった.例えば、一般関数:
function F(){
}
alert(F.prototype instanceof Object) //true
構造関数、すなわちオブジェクトを作成します.まず,構造関数を通してオブジェクトを実用化する過程を理解した.
function A(x){
  this.x=x;
}
var obj=new A(1);
具体化されたObjectオブジェクトは3ステップあります.1.Objオブジェクトの作成:obj=new Object()2.objの内部protoを彼の関数Aを構成するprototypeに向けると同時に、obj.com structor==A.prototype.com nstructor(これは永遠に成立しています.A.prototypeが元のAプロトタイプに向かなくても、つまり、クラスのインスタンスオブジェクトのconstrutor属性は永遠に「構造関数」のprototypenstructorを指します.)したがって、obj.com nstructor.prototypeは、A.prototypeを指します.Obj.com nstructor.prototypeとの内部protoは別個のことであり、具体的にはプロト、objにはプロトタイプがありませんが、内部プロトがあり、プロトによってプロトタイプ属性とプロトタイプ方法を取得します.FireFoxにプロトを公開しました.FireFoxにおいてalert(obj.proto)があります.3.Objをthisとして構造関数Aを呼び出し、メンバー(すなわちオブジェクト属性とオブジェクト方法)を設定し、初期化する.この3ステップが完了すると、このObjオブジェクトはコンストラクタAとは無関係になります.このとき、コンストラクタAにメンバーを加えても、すでに実用化されているObjオブジェクトには影響を与えません.このとき、Objオブジェクトはx属性を持ちながら、構造関数Aのプロトタイプオブジェクトの全メンバーを有しているが、このプロトタイプオブジェクトにはメンバーがいない.プロトタイプのオブジェクトは最初は空で、つまりプロトタイプの属性とプロトタイプの方法です.プロトタイプオブジェクトがどれぐらいのメンバーを持っているかは以下の方法で検証できます.
var num=0;
for(o in A.prototype) {
  alert(o);//alert       
  num++;
}
alert("member: " + num);//alert         。
しかし,プロトタイプ属性またはプロトタイプ法が定義されると,このコンストラクタによって実証されたすべてのオブジェクトは,これらのプロトタイプ属性とプロトタイプ法を継承し,これは内部のプロトチェーンによって達成される.例えば、A.prototype.say=function(){alert("Hi")}すべてのAのオブジェクトはsay方法を持っています.このモデルのオブジェクトのsay方法は唯一のコピーで共有されています.オブジェクトごとにsay方法のコピーがあります.
二.原型と継承
まず、簡単な継承の実現を見ます.
1 function A(x){
2   this.x=x;
3 }  
4  function B(x,y){
5   this.tmpObj=A;
6   this.tmpObj(x);
7   delete this.tmpObj;
8   this.y=y;
9 }
第5、6、7行:一時属性tmpObj参照構造関数Aを作成し、Bの内部で実行し、実行後に削除します.Bはもちろんx属性を持っています.もちろんBのx属性とAのx属性は独立していますので、厳密な継承とは言えません.5、6、7行目はもっと簡単な実現があります.コール方法:A.call(this,x);これらの2つの方法はいずれもAの実行にthisを伝達しています.thisはBのオブジェクトを指しています.これはなぜ直接A(x)がないのですか?このような継承方式はクラス継承(jsはクラスがなく、ここではただ構造関数を指す)であり、A構造オブジェクトの属性方法はすべて継承されていますが、Aの原型オブジェクトのメンバーは継承できません.この目的を達成するには、その上に原型を加えて継承することです.次の例を通して、原型や原型の参画による完璧な継承が深く分かります.
 1  function A(x){
 2    this.x = x;
 3  }
 4  A.prototype.a = "a";
 5  function B(x,y){
 6    this.y = y;
 7    A.call(this,x);
 8  }
 9  B.prototype.b1 = function(){
10    alert("b1");
11  }
12  B.prototype = new A();
13  B.prototype.b2 = function(){
14    alert("b2");
15  }
16  B.prototype.constructor = B;
17  var obj = new B(1,3);
この例はBがAを継ぐということです.第7行クラス継承:A.cal(this.x)上に述べました.原型継承を実現したのは12行目:B.prototype=new A();
つまり、BのプロトタイプをAの1つのインスタンスオブジェクトに向けています.この例のオブジェクトはx属性を持ち、undefinedであり、a属性もあり、値はaです.したがって、Bプロトタイプもこの2つの属性を持っています.すなわち、BとAはプロトタイプチェーンを作っています.BはAの下位です.先ほどのクラス継承のため、Bのインスタンスオブジェクトもx属性を持っています.つまり、objオブジェクトは2つの同名のx属性を持っています.この場合、プロトタイプ属性xはインスタンスオブジェクト属性xに位置するので、Obj.xはundefinedではなく、1です.13行目はまたプロトタイプ方法b 2を定義していますので、Bプロトタイプもb 2を持っています.9行目から11行目にプロトタイプ方法b 1が設定されていますが、12行目の実行後、Bプロトタイプはb 1の方法を持たなくなりました.つまり、Obj.b 1はundefinedです.第12行使のBプロトタイプは変更されたため、b 1を持つ元のプロトタイプのオブジェクトは放棄され、もちろんb 1はなくなりました.12行目の実行後、BプロトタイプはAのインスタンスオブジェクトを指し、AのインスタンスオブジェクトのコンストラクタはコンストラクタAであるため、B.prototype.com stuctorはオブジェクトAを構成している(換言すれば、AはBのプロトタイプを構築している).alert(B.prototype.com nstructor)が出てきたら、「function A(x){}」です.同様に、obj.com nstructorもA構造の対象であり、alert(obj.com nstructor)が出たら「function A(x){}」、つまりB.prototype.com nstructor==obj.touctor(true)が出てきますが、B.prototype==job.touctouctor.protobtypeの原型を持っています.この問題をどう修正すればいいですか?16行目にBプロトタイプのコンストラクタをBコンストラクタにもう一度指したら、B.prototype==obj.com nstructor.prototype(true)ともメンバーがいます.
もし16行目がなかったら、Obj=new B(1,3)はAコンストラクタの実用化を呼び出すのですか?答えは否定的です.obj.y=3を見つけることができますので、やはり呼び出しのBコンストラクターが実用化されています.Obj.com nstructor==A(true)が、new B()の動作については、上記のように構成関数によってインスタンスオブジェクトを作成する3つのステップが実行され、第1ステップは空のオブジェクトを作成する.第二のステップは、Obj.prototype==B.prototype、B.prototypeはx、a、b 2のメンバーの、Obj.com nstructorはB.prototype.com nstructorを指しています.つまり、構造関数Aです.第三段階では、呼び出したコンストラクターBは、属性x,yを持つメンバーを設定し、初期化する.16行をプラスしないとobjの属性に影響しませんが、上記のように、obj.com nstructorとobj.com nstructor.prototypeに影響を与えます.原型継承を使用した後、修正作業を行います.12行目、16行目については、総じて、第12行BプロトタイプはAのプロトタイプの全メンバーを継承していますが、BのインスタンスオブジェクトのコンストラクタのプロトタイプはAプロトタイプを指していますので、16行目でこの欠陥を修正します.