JavaScript オブジェクト指向プロトタイプと継承_js オブジェクト指向

WBOY
リリース: 2016-05-16 17:51:56
オリジナル
1092 人が閲覧しました
1. はじめに

この記事は、Microsoft のマスター Scott Allen Prototypes and Inheritance in JavaScript から翻訳されたもので、プロトタイプとは何か、およびプロトタイプによって継承が実現できる理由について詳細な分析と説明を提供します。 . JS OO を理解するのに最適な作品の 1 つです。翻訳が良くない場合は、修正して追加してください。

2. テキスト
JavaScript のオブジェクト指向は他の言語とは異なります。学習する前に、よく知っているオブジェクト指向の概念を忘れるのが最善です。 JS の OO は、より強力で、より議論的で、より柔軟です。

1. クラスとオブジェクト
JS は、伝統的な観点から見たオブジェクト指向言語です。プロパティと動作は 1 つのオブジェクトに結合されます。たとえば、JS の配列は、プロパティとメソッド (プッシュ、リバース、ポップなど) で構成されるオブジェクトです。
コードをコピー コードは次のとおりです。

var myArray = [1, 2];
myArray.push(3);
myArray.reverse();
var length = myArray.length; : これらのメソッド (プッシュはどこから来たのか)一部の静的言語 (JAVA など) では、クラスを使用してオブジェクトの構造を定義します。しかし、JS は「クラス」のない言語 (クラスレス) であり、配列ごとに継承するこれらのメソッドを定義する「Array」というクラスがありません。 JS は動的であるため、必要に応じてオブジェクトにメソッドを自由に追加できます。たとえば、次のコードは、2 次元空間の座標を表すオブジェクトを定義し、その中に add メソッドが含まれています。



コードをコピーy : 5,
add: function(otherPoint)
{
this.x = otherPoint.x;
this.y = otherPoint.y; >};


すべてのポイント オブジェクトに add メソッドが必要です。また、すべてのポイント オブジェクトに add メソッドを追加することなく、すべてのポイント オブジェクトが add メソッドを共有できることを望んでいます。これにはプロトタイプが現れる必要があります。

2. プロトタイプについて
JS のすべてのオブジェクトには暗黙の属性 (状態) があり、これは、上で作成したオブジェクトの配列とポイントと呼ばれます。それぞれのプロトタイプへの参照が含まれています。プロトタイプ参照は暗黙的ですが、ECMAScript が実装したものであり、オブジェクトの _proto_ (Chrome の) プロパティを使用して取得できます。概念的に理解すると、以下の図に示すように、オブジェクトとプロトタイプの関係を考えることができます。



開発者として、_proto_ 属性の代わりに Object.getPrototypeOf 関数を使用して、オブジェクトのプロトタイプ参照を表示します。この記事の執筆時点では、Object.getPrototypeOf 関数は Chrome、Firefox、IE9 でサポートされています。将来的には、さらに多くのブラウザがこの機能をサポートする予定です。この機能はすでに ECMAScript 標準の 1 つです。次のコードを使用して、前に作成した myArray と point オブジェクトが実際に 2 つの異なるプロトタイプ オブジェクトを参照していることを証明できます。

prototype1コードをコピー



コードは次のとおりです。
Object.getPrototypeOf(point) != オブジェクト .getPrototypeOf(myArray);

この記事の残りの部分では、_proto_ も使用します。主に、図や文章では _proto_ の方が直感的であるためです。ただし、これは正規ではないことに注意してください。オブジェクトのプロトタイプを取得するには、Object.getPrototypeOf が推奨されるメソッドです。

2.1 プロトタイプはなぜ特別なのでしょうか?

配列のプッシュ メソッドが myArray のプロトタイプ オブジェクトから来ていることはすでにわかっています。図 2 は、Chrome でのスクリーンショットです。Object.getPrototypeOf メソッドを呼び出して、myArray のプロトタイプ オブジェクトを取得します。

ff852808_img002(en-us,MSDN_10)

図 2

myArray のプロトタイプ オブジェクトには、最初のコードで使用した、push、pop、reverse などの多くのメソッドが含まれていることに注目してください。 。プロトタイプ オブジェクトは、push メソッドの唯一の所有者ですが、このメソッドは myArray を通じてどのように呼び出されるでしょうか?
コードをコピーします コードは次のとおりです。

myArray.push(3); >
Protytype がどのように実装されているかを理解するための最初のステップは、Protytype がまったく特別なものではないことを理解することです。プロトタイプはオブジェクトです。他の JS オブジェクトと同様に、これらのオブジェクトにメソッドとプロパティを追加できます。しかし同時に、Prototype は特別なオブジェクトでもあります。

プロトタイプは次のルールにより特別です。オブジェクトのプッシュ メソッドを呼び出すか、特定のプロパティを読み取りたいことを JS に通知すると、インタプリタ (ランタイム) はまずオブジェクト自体のメソッドまたはプロパティを探します。 。インタプリタがメソッド (または属性) を見つけられない場合、_proto_ 参照に従ってオブジェクトのプロトタイプ内の各メンバーを見つけます。 myArray で Push メソッドを呼び出すと、JS は myArray オブジェクトで Push を見つけませんが、myArray のプロトタイプ オブジェクトで Push を見つけます。つまり、push メソッドが呼び出されます (図 3)。

ff852808_img003(en-us,MSDN_10)図 3


私が説明した動作は、基本的に、オブジェクト自体がそのプロトタイプからすべてのメソッドとプロパティを継承するというものです。この継承関係を JS で実装するためにクラスを使用する必要はありません。つまり、JS オブジェクトはそのプロトタイプからプロパティを継承します。

図 3 は、各配列オブジェクトが独自の状態とメンバーを維持できることも示しています。 myArray の長さプロパティが必要な場合、JS はプロトタイプ内で長さの値を探すことなく、myArray から長さの値を見つけます。この機能を使用してメソッドを「オーバーライド」することができます。つまり、オーバーライドする必要があるメソッド (プッシュなど) を myArray 独自のオブジェクトに入れることができます。これにより、プロトタイプ内のプッシュ メソッドを効果的に隠すことができます。

3. プロトタイプの共有
JS のプロトタイプの本当の魅力は、複数のオブジェクトが同じプロトタイプ オブジェクトを参照できることです。たとえば、2 つの配列を作成します:

コードをコピー コードは次のとおりです:
var myArray = [ 1, 2];var yourArray = [4, 5, 6];

2 つの配列は同じプロトタイプ オブジェクトを共有し、次のコードは true を返します

コードをコピー コードは次のとおりです:
Object.getPrototypeOf(myArray) === Object.getPrototypeOf(yourArray) ;


2 つの配列でプッシュ メソッドを呼び出すと、JS は共通のプロトタイプでプッシュ メソッドを呼び出します。

ff852808_img004(en-us,MSDN_10)

プロトタイプ オブジェクトは、JS でこの継承機能を提供し、メソッドの実装を共有することもできます。プロトタイプも連鎖します。言い換えれば、プロトタイプはオブジェクトであり、プロトタイプ オブジェクトは別のプロトタイプ オブジェクトへの参照を持つこともできます。図 2 からわかるように、プロトタイプの _proto_ 属性は null 以外の値であり、JS がプッシュ メソッドなどのメンバー変数を探し始めると、これらの各プロトタイプ参照をチェックします。このオブジェクトが見つかるか、チェーンの終端に到達するまで。このチェーン方式により、JS での継承と共有の柔軟性が高まります。

次に、カスタム オブジェクトのプロトタイプ参照を設定するにはどうすればよいでしょうか?たとえば、前に作成したオブジェクト ポイントの場合、すべてのポイント オブジェクトがそれを継承できるように、プロトタイプ オブジェクトに add メソッドを追加するにはどうすればよいでしょうか。この質問に答える前に、まず JS の関数について理解しましょう。

4. 関数について
JS では関数もオブジェクトです。関数には JS の重要な機能が多数あり、この記事ではすべてをリストすることはできません。ただし、関数を変数に代入したり、関数を別の関数のパラメーターとして使用したりすることは、今日の JS プログラミングにおける非常に基本的な方法です。

注意する必要があるのは、関数はオブジェクトであるため、メソッド、プロパティ、プロトタイプ オブジェクトへの参照を持っているということです。次のコードの意味について説明します:
コードをコピー コードは次のとおりです:

// これは true を返します:
typeof (Array) === "function"
// そして次も同様です:
Object.getPrototypeOf(Array) === Object.getPrototypeOf(function () { })
// そしてこれも:
Array.prototype != null

コードの最初の行は、Array が JS の関数であることを証明しています。後で、Array 関数を呼び出して新しい配列オブジェクトを作成する方法を説明します。

コードの 2 行目は、すべての配列オブジェクトがプロトタイプを共有していることを前に見たのと同様に、Array オブジェクトと関数オブジェクトが同じプロトタイプを参照していることを証明しています。

最後の行は、Array 関数がプロトタイプ属性を持つことを証明しています。このプロトタイプ属性を _proto_ 属性と混同しないでください。使用目的や指す対象が異なります。
コードをコピー コードは次のとおりです:

// true
Array.prototype == Object .getPrototypeOf(myArray)
// これも true
Array.prototype == Object.getPrototypeOf(yourArray);

新しい知識を使用して前の図を再描画します。 🎜 >

ff852808_img005(en-us,MSDN_10)

図 5

次に、配列オブジェクトを作成する必要があります。メソッドの 1 つは次のとおりです:


コードをコピーします コードは次のとおりです:
//新しい空のオブジェクトを作成します
var o = {};
// 配列オブジェクトとして同じプロトタイプを継承します
o.__proto__ = Array.prototype
// これで、任意のオブジェクトを呼び出すことができます。配列メソッドの ...
o.push(3);
上記のコードは適切に見えますが、問題は、すべての JS 環境がオブジェクトの _proto_ 属性をサポートしているわけではないことです。幸いなことに、JS には、新しいオブジェクトを作成し、オブジェクトの _proto_ プロパティを設定するための標準の組み込みメカニズムが備わっています。これが「new」演算子です。
コードをコピーします コードは次のとおりです。

var o = new Array(); 🎜>o .push(3);

JS では、「new」演算子には 3 つの重要なタスクがあります。まず、新しい空のオブジェクトを作成します。次に、この新しいオブジェクトの _proto_ 属性が、呼び出し側関数のプロトタイプ属性を指すように設定されます。最後に、呼び出し関数が実行され、「this」ポインタが新しいオブジェクトを指します。上記の 2 行のコードを展開すると、次のコードが得られます。

コードをコピー コードは次のとおりです。
var o = {};
o.__proto__ = Array.call(o);


関数の「call」メソッドを使用すると、関数を呼び出して、関数内の「this」が渡された新しいオブジェクトを指すように指定できます。もちろん、オブジェクトの継承を実現するために、上記のメソッドを通じて独自のオブジェクトを作成することもできます。この関数は、私たちがよく知っているコンストラクターです。
5. コンストラクター
コンストラクターは、2 つの一意の識別子を持つ共通の JS 関数オブジェクトです:

1. 最初の文字は大文字です (識別しやすい)。

2. 新しい演算子接続を使用して新しいオブジェクトを構築します。

配列はコンストラクターです。配列関数は new に接続され、最初の文字は大文字になります。 JS の Array 関数は組み込みですが、誰でも独自のコンストラクターを作成できます。実際、いよいよ point オブジェクトのコンストラクターを作成します。




コードをコピー コードは次のとおりです。 var Point = function (x , y) {
this.x = x;
this.y = y;
this.add = function (otherPoint) {
this.x =
this. y = otherPoint .y;
}
}
var p1 = new Point(3, 4)
var p2 = new Point(8, 6); );


上記のコードでは、new 演算子と Point 関数を使用してポイント オブジェクトを構築します。メモリ内では、図 6 に示すような最終結果を考えることができます。



図 6 ff852808_img006(en-us,MSDN_10)問題は、add メソッドがすべてのポイント オブジェクトに存在することです。プロトタイプについての知識を考慮すると、(add メソッドのコードをすべてのオブジェクトにコピーする必要がなく) Point.prototype に add メソッドを追加する方が良い選択になります。この目的を達成するには、Point.prototype オブジェクトにいくつかの変更を加える必要があります。





コードをコピー
コードは次のとおりです。 var Point = function (x , y) { this.x = x;
this.y = y;
Point.prototype.add = function (otherPoint) {
this.x = otherPoint.x ;
this.y = otherPoint.y;
}
var p1 = 新しいポイント(3, 4)
var p2 = 新しいポイント(8, 6); (p2) ;


わかりました!プロトタイプを使ってJSで継承を実装しました!




6. 概要
この記事がプロトタイプの霧を晴らすのに役立つことを願っています。もちろん、これは強力で柔軟なプロトタイプの単なる紹介にすぎません。読者がプロトタイプについて自分で調べてさらに発見できることを願っています。
関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!