ホームページ > 記事 > ウェブフロントエンド > JavaScriptのプロトタイプとプロトタイプチェーンを詳しく解説_基礎知識
JavaScript のすべてのオブジェクトには、組み込みの属性プロトタイプがあります。JavaScript のオブジェクトのプロトタイプ属性の説明は次のとおりです。オブジェクト型のプロトタイプへの参照を返します。これは、prototype 属性が、現在のオブジェクトの親オブジェクトとして機能する別の JavaScript オブジェクトへの参照を保持していることを意味します。
引き続き以下の分析を読んでください:
プライベート変数と関数
関数内で定義された変数と関数は、外部へのインターフェイスが提供されていない場合、つまり変数と関数が関数に対してプライベートである場合、外部からアクセスすることはできません。
}
}
静的変数と静的関数
関数が定義され、ドット「.」によって追加された属性と関数はオブジェクト自体からアクセスできますが、そのインスタンスにはアクセスできない場合、そのような変数と関数はそれぞれ静的変数と静的関数と呼ばれます。
Obj.num = 72;//静的変数
Obj.fn = function() //静的関数
{
}
alert(Obj.num);//72
alert(obj.fn の種類)//function
var t = new Obj();
alert(t.name);//未定義
alert(typeof t.fn);//未定義
インスタンス変数と関数
オブジェクト指向プログラミングでは、いくつかのライブラリ関数に加えて、オブジェクトの定義時に同時にいくつかのプロパティとメソッドを定義することが望まれます。これらはインスタンス化後にアクセスできます。
}
}
console.log(typeof Box.a) //未定義
console.log(Box.fn の種類); //未定義
var box=new Box();
console.log(box.a のタイプ); //オブジェクト
console.log(box.fn のタイプ); //関数
インスタンス変数とメソッドの新しいメソッドとプロパティを追加します
}
}
var box1=new Box();
box1.a.push(1);
box1.fn={};
console.log(box1.a); //[1]
console.log(box1.fn のタイプ); //オブジェクト
var box2=new Box();
console.log(box2.a); //[]
console.log(box2.fn のタイプ); //関数
A と fn は box1 では変更されますが、box2 では変更されません。配列と関数はどちらもオブジェクトであり参照型であるため、box1 のプロパティとメソッドは box2 のものと同じ名前ですが、ただし、これは参照ではなく、Box オブジェクトによって定義されたプロパティとメソッドのコピーです。
これは属性にとっては問題ではありませんが、メソッドにとっては大きな問題です。メソッドはまったく同じ機能を実行しますが、関数オブジェクトに 1000 のメソッドとインスタンスのメソッドがある場合、それぞれのインスタンスが 2 回コピーされるからです。何千ものメソッドのコピーを維持する必要がありますが、これは明らかに非科学的です。プロトタイプが誕生しました。
基本概念
私たちが作成するすべての関数には、オブジェクトへのポインターであるプロトタイプ属性があります。このオブジェクトの目的は、特定の型のすべてのインスタンスで共有できるプロパティとメソッドを含めることです。そして、prototypeはコンストラクタを呼び出して作成されるオブジェクトインスタンスのプロトタイプオブジェクトです。
プロトタイプを使用する利点は、オブジェクト インスタンスがそれに含まれるプロパティとメソッドを共有できることです。つまり、コンストラクターに定義オブジェクト情報を追加する代わりに、この情報をプロトタイプに直接追加できます。コンストラクターを使用する場合の主な問題は、各インスタンスで各メソッドを作成する必要があることです。
JavaScriptには、プリミティブ値とオブジェクト値の2種類の値があります。すべてのオブジェクトには、通常プロトタイプと呼ばれる内部プロパティ プロトタイプがあります。プロトタイプの値はオブジェクトまたは null にすることができます。その値がオブジェクトの場合、そのオブジェクトにも独自のプロトタイプが必要です。これにより、プロトタイプ チェーンと呼ばれる線形チェーンが形成されます。
意味
関数はコンストラクターとして使用できます。さらに、関数のみがプロトタイプ属性を持ち、アクセスできますが、オブジェクト インスタンスにはこの属性はなく、アクセスできない内部の __proto__ 属性のみが存在します。 __proto__ は、オブジェクト内の関連するプロトタイプへの暗号的なリンクです。標準によれば、__proto__ は公開されていません。つまり、プライベート プロパティですが、Firefox エンジンは、外部からアクセスして設定できるパブリック プロパティとして公開します。
var Bro = 新しいブラウザ();
Bro.run();
Bro.run() メソッドを呼び出すと、Bro にはそのようなメソッドがないため、その __proto__ にアクセスしてそれを見つけます。これが Browser.prototype であり、最終的に run() メソッドが実行されます。 (ここでは、通常の関数と区別するため、関数の最初の文字を大文字でコンストラクタを表します)
インスタンスを作成するためにコンストラクターが呼び出されるとき、インスタンスにはコンストラクターのプロトタイプを指す内部ポインター (__proto__) が含まれます。この接続は、インスタンスとコンストラクターのプロトタイプの間に存在します。インスタンスとコンストラクターの間には存在しません。コンストラクター。
{
アラート(this.name);
}
console.log(person1.__proto__);//人
console.log(person1.constructor);// 自分で試して、何が起こるか見てみましょう
console.log(Person.prototype);//プロトタイプ オブジェクト Person
へのポイント
var person2=新しい人('フランク');
すべての JavaScript 関数には、プロトタイプ属性があります。この属性は、プロトタイプ オブジェクトであるオブジェクトを参照します。プロトタイプ オブジェクトは初期化時には空です。その中のプロパティとメソッドはカスタマイズでき、これらのメソッドとプロパティはコンストラクターによって作成されたオブジェクトに継承されます。
さて、ここからが問題です。コンストラクター、インスタンス、プロトタイプ オブジェクトの関係は何ですか?
コンストラクター、インスタンス、プロトタイプ オブジェクトの違いインスタンスはコンストラクターを通じて作成されます。インスタンスが作成されると、そのインスタンスにはコンストラクター属性 (コンストラクターを指す) と __proto__ 属性 (プロトタイプ オブジェクトを指す) が含まれます。
コンストラクターにはプロトタイプ属性があり、これはプロトタイプ オブジェクトを指すポインターです。
プロトタイプ オブジェクト内には、コンストラクターを指すポインター (コンストラクター属性) もあります: Person.prototype.constructor = Person;
インスタンスは、プロトタイプ オブジェクトで定義されたプロパティとメソッドにアクセスできます。
ここで person1 と person2 はインスタンスであり、prototype はそれらのプロトタイプ オブジェクトです。
別の例:
alert("これは " this.name);
}
var Dog = new Animal("dog");//Dog オブジェクトを作成します
Dog.behavior();//Dog オブジェクトを通じて Behavior メソッドを直接呼び出します
alert(Dog.behavior==Cat.behavior);//出力 true;
プログラムの実行結果から、コンストラクターのプロトタイプで定義されたメソッドが実際にオブジェクトを通じて直接呼び出すことができ、コードが共有されていることがわかります。 (Animal.prototype.behavior のプロトタイプ属性を削除して、まだ機能するかどうかを確認してください。) ここで、プロトタイプ属性は Animal オブジェクトを指しています。
配列オブジェクトインスタンス
配列オブジェクトの例を見てください。オブジェクト array1 を作成するとき、JavaScript エンジンにおける array1 の実際のオブジェクト モデルは次のようになります:
array1 オブジェクトの長さ属性値は 3 ですが、次のメソッドを通じて array1 に要素を追加できます:
関数オブジェクトインスタンス
新しいオペレーターは具体的に何をするのですか? それは実際には非常に単純で、3 つのことを行います。
プロトタイプ チェーン: オブジェクトからプロパティまたはメソッドを呼び出すとき、オブジェクト自体にそのようなプロパティまたはメソッドがない場合、プロトタイプにプロパティまたはメソッドがない場合は、関連付けられたプロトタイプ オブジェクトに移動して探します。プロトタイプの関連付けに移動して、前のプロトタイプを検索し、それ以上ない場合は、Prototype...Prototype が未定義になるまで (オブジェクトのプロトタイプが未定義になるまで) Prototype.Prototype によって参照されるオブジェクトの検索を続けます。 )、いわゆる「プロトタイプチェーン」を形成します。
コードをコピーします
ここでは、コンストラクター Shape() を使用して新しいエンティティが作成され、オブジェクトのプロトタイプをオーバーライドするために使用されます。
TwoShape.prototype = new Shape();
Triangle.prototype = new TwoShape();
TwoShape.prototype.constructor = TwoShape;
Triangle.prototype.constructor = Triangle;
var my = new Triangle(5,10);
My.getArea();
My.toString();//Triangle
My.constructor;//Triangle(side,height)
プロトタイプの継承
プロトタイプの継承: プロトタイプ チェーンの最後にあるのは、オブジェクト コンストラクターのプロトタイプ属性によって指定されるプロトタイプ オブジェクトです。このプロトタイプ オブジェクトはすべてのオブジェクトの祖先であり、すべてのオブジェクトが本質的に持つべき toString などのメソッドを実装します。 Function、Boolean、String、Date、RegExp などの他の組み込みコンストラクターのプロトタイプはすべてこの祖先から継承されていますが、それらはそれぞれ独自のプロパティとメソッドを定義しているため、子孫はそれぞれのクランの特性を示します。それらの特徴。
ECMAScript では、継承を実装する方法はプロトタイプ チェーンに依存することです。
function Tree(){ //継承された関数はサブタイプ(サブクラス、派生クラス)と呼ばれます
This.age = 300;
}
//プロトタイプチェーンの継承を通じて、サブタイプのプロトタイププロパティに値を割り当てます
//new Box() はボックス構造内の情報とプロトタイプを Tree
に渡します
Tree.prototype = new Box();//Tree は Box を継承し、プロトタイプを通じてチェーンを形成します
var ツリー = new Tree();
alert(tree.name);//ポップアップジャック
プロトタイプ チェーンの問題: プロトタイプ チェーンは非常に強力で、継承の実装に使用できますが、いくつかの問題もあります。そのうちの主なものは、参照型を含む値プロトタイプに由来します。参照型を含むプロトタイプ プロパティはすべてのインスタンスで共有されます。これが、プロパティがプロトタイプ オブジェクトではなくコンストラクターで定義される理由です。プロトタイプを介して継承が実装されると、プロトタイプは実際には別の型のインスタンスに戻ります。その結果、元のインスタンス プロパティがプロトタイプ プロパティになります。
サブタイプのインスタンスを作成する場合、パラメーターをスーパータイプのコンストラクターに渡すことはできません。実際、すべてのオブジェクト インスタンスに影響を与えずにスーパータイプのコンストラクターにパラメーターを渡す方法はないと言うべきです。プロトタイプに参照型の値が含まれるために今説明した問題と相まって、プロトタイプ チェーンだけが実際に使用されることはほとんどありません。
別の例:
person.prototype.company = "Microsoft";//プロトタイプのプロパティを設定します
Person.prototype.SayHello = function() //プロトタイプメソッド
{
alert("こんにちは、" this.company の " this.name " です);
};
var BillGates = new Person("BillGates");//人物オブジェクトを作成します
BillGates.SayHello();//プロトタイプの内容を継承し、「こんにちは、Microsoft の BillGates です」を出力します
var Jobs = new Person("Jobs");
Jobs.company = "Apple";//プロトタイプの会社属性をカバーして、独自の会社属性を設定します
Jobs.SayHello = function()
{
alert("こんにちは、" this.name " like " this.company);
};
Jobs.SayHello();//属性とメソッドを自分でオーバーライドし、「Hi, Jobs like Apple」を出力します
BillGates.SayHello();//ジョブのカバレッジはプロトタイプには影響せず、BillGates は引き続き
を出力します
次のプロトタイプ チェーンの例を見てください:
}
};
関数 Hi(){
};
//Hi のプロトタイプ属性を Year
のインスタンス オブジェクトに設定します
Hi.prototype = new Year();
Hi.prototype.year = 'Hello World';
Hi.prototype.constructor = こんにちは;
var test = new Hi();//Hi の新しいインスタンスを作成します
//プロトタイプチェーン
[こんにちはインスタンス] をテストします
Hi.prototype [年のインスタンス]
{年:'Hello World'}
年.プロトタイプ
に
object.prototype
__ptoto__ 属性 (IE ブラウザではサポートされていません) は、インスタンスからプロトタイプ オブジェクトへのポインターであり、その機能は、コンストラクターのプロトタイプ属性コンストラクターを指すことにより、属性とメソッドにアクセスできます。プロトタイプでは。
JavaScript のオブジェクト インスタンスは、基本的に一連の属性で構成されます。これらの属性の中に、内部の目に見えない特別な属性 (__proto__) があり、この属性の値はオブジェクト インスタンスのみが持つプロトタイプを指します。ユニークなプロトタイプ。
var box2 = new Box();
alert(box1.constructor);//構築属性、コンストラクタ自体を取得できます、
//関数はプロトタイプ ポインターによって配置され、コンストラクター自体を取得します
スクリプト>
__proto__ 属性とプロトタイプ属性の違い
プロトタイプは関数オブジェクトの独自の属性です。
__proto__ は通常のオブジェクトの暗黙的な属性です。 new を使用すると、
が指すオブジェクトを指します。
__ptoto__ は実際にはエンティティ オブジェクトの属性ですが、プロトタイプはコンストラクターに属する属性です。 __ptoto__ は学習環境またはデバッグ環境でのみ使用できます。
プロトタイプモードの実行処理
1. まず、コンストラクター インスタンス内の属性またはメソッドを検索し、存在する場合はすぐに返します。
2. コンストラクターのインスタンスがない場合は、そのプロトタイプ オブジェクト内でそれを探します。存在する場合は、すぐに戻ります
。
プロトタイプオブジェクトの
box1.name = "リー";
alert(box1.name);//リー、原則を入力してください
var box2 = new Box();
によって変更されていません
{
return this.name this.age '勉強中';
}
var box1 = new Box();
alert(box1.name);//Bill、プロトタイプの値
alert(box1.name);//リー、原則を入力してください
まとめると、次のように整理しましょう:
person.prototype.name = "trigkit4";
person.prototype.say = function(){
alert("こんにちは");
}
var p1 = new Person();//prototype は p1 と p2 のプロトタイプ オブジェクトです
var p2 = new Person();//p2 はインスタンス化されたオブジェクトであり、内部 __proto__ 属性を持ち、Person のプロトタイプを指します
console.log(p1.prototype);//未定義、このプロパティはオブジェクトであるためアクセスできません
console.log(person.prototype);//人
console.log(Person.prototype.constructor);//プロトタイプ オブジェクト内には、コンストラクター
を指すポインター (コンストラクター属性) もあります。
console.log(p1.__proto__);//この属性はプロトタイプのプロトタイプオブジェクトへのポインタです
p1.say();//インスタンスはプロトタイプ オブジェクトで定義されたプロパティとメソッドにアクセスできます
工場出荷時モード
ファクトリ パターンは、インスタンス化されたオブジェクトの大量の重複の問題を解決しますが、別の問題があります。それは、それらがどのオブジェクトのインスタンスであるかを把握することが不可能であるということです。
コンストラクター メソッドを使用すると、インスタンス化の繰り返しの問題が解決されるだけでなく、オブジェクトの識別の問題も解決されます。
コンストラクター メソッドとファクトリ パターンの使用の違いは次のとおりです。
1. コンストラクター メソッドは、作成されたオブジェクト (new Object()) を表示しません。
2. このオブジェクトにプロパティとメソッドを直接割り当てます
3. return ステートメントはありません
コンストラクターが使用され、newconstructor() が使用されると、new Object() がバックグラウンドで実行されます。
関数本体のこれは、 new Object()
によって生成されたオブジェクトを表します。
2. コンストラクター属性を使用してリテラルが作成される方法は、インスタンスを指すのではなく、オブジェクトを指すようになります。コンストラクターの作成方法は逆です。
なぜオブジェクトを指すのでしょうか? Box.prototype = {}; なので、この書き方では実際に新しいオブジェクトが作成されます。
関数が作成されるたびに、そのプロトタイプも同時に作成され、このオブジェクトはコンストラクター属性
も自動的に取得します。
3. インスタンス メソッドの場合、異なるインスタンス化には異なるメソッド アドレスがあり、一意です
4. プロトタイプメソッドの場合、アドレスは共有されます