あなたが以前に学んだすべてのオブジェクト指向の知識を忘れてください。ここでレースの状況を考えてみてください。はい、それはレースです。
最近、フランスで人気のあるイベントである24時間のルマンを見ています。最速の車は、Le Mansプロトタイプと呼ばれます。これらの車は「アウディ」や「プジョー」などのメーカーによって作られていますが、路上や高速道路で見られる車の種類ではありません。それらは、高速耐久イベントのために特別に作られています。
メーカーは、これらのプロトタイプ車を開発、設計、製造するために多額のお金を投資し、エンジニアは常にこのプロジェクトを極端にしようとします。彼らは、合金、バイオ燃料、ブレーキ技術、複合組成、タイヤの安全特性に関するさまざまな実験を実施しました。時間が経つにつれて、これらの実験のいくつかの技術は繰り返し改善され、車両の主流製品ラインに入りました。運転している車両のテクノロジーの一部は、レースのプロトタイプでデビューした可能性があります。
また、これらの主流の車両は、レーシングカーから技術的なプロトタイプを継承していると言えます。
これまで、JavaScriptのプロトタイプと相続の問題について議論するための基礎があります。 C ++、Java、またはC#で知っている古典的な継承パターンほど良くありませんが、それは同じくらい強力で潜在的に柔軟性があります。
JavaScriptには、伝統的な意味でのオブジェクト、つまり「状態と行動を含む単一のエンティティ」を指すオブジェクトがいっぱいです。たとえば、JavaScriptの配列は、いくつかの値を含み、プッシュ、リバース、およびPOPメソッドを含むオブジェクトです。
var myarray = [1、2]; myarray.push(3); myarray.reverse(); myarray.pop(); var length = myarray.length;
今、問題は、プッシュはどこから来たのかということです。以前に言及した静的言語は、「クラスの構文」を使用してオブジェクトの構造を定義しますが、JavaScriptは「クラスの構文」のない言語であり、配列の構文「クラス」を使用して各配列オブジェクトを定義することはできません。また、JavaScriptは動的な言語であるため、実際に必要なオブジェクトにメソッドを配置できます。たとえば、次のコードは、2次元空間のポイントを表すために使用されるポイントオブジェクトを定義し、ADDメソッドも定義します。
var point = {x:10、y:5、add:function(otherpoint){this.x += otherpoint.x; this.y += otherpoint.y; }};ただし、上記のプラクティスはあまりスケーラブルではありません。各ポイントオブジェクトにADDメソッドが含まれていることを確認する必要があります。また、このメソッドを各ポイントオブジェクトに手動で追加するのではなく、すべてのポイントオブジェクトに同じ追加メソッドの実装を共有する必要があります。これは、プロトタイプが登場する場所です。
JavaScriptでは、各オブジェクトは隠されたままです - プロトタイプとも呼ばれる別のオブジェクトへの参照。作成した配列は、プロトタイプオブジェクトを参照するアレイであり、自分で作成したポイントオブジェクトも参照します。上記のように、プロトタイプの参照は非表示ですが、オブジェクトの__Proto__属性(Google Chromeなど)を介してこのプロトタイプ参照にアクセスできるECMAScript(JavaScriptの公式名)の実装もあります。概念的には、オブジェクトを図1プロトタイプに示すものと同様の関係として扱うことができます。
図1
先を見ると、開発者は__Proto__属性の代わりにObject.GetPrototypeof関数を使用して、オブジェクトプロトタイプへの参照を取得できます。この記事を書いている時点で、Object.getPrototypeof関数は、Google Chrome、Firefox、およびIE9ブラウザーで既に使用できます。より多くのブラウザは、将来この機能を将来的に実装します。これは、ECMAScript標準の一部であるためです。次のコードを使用して、作成したMyArrayおよびDOTオブジェクトが2つの異なるプロトタイプオブジェクトを参照していることを証明できます。
この記事の残りの部分では、__Proto __.getProtopeof関数を交差します。これは、主に__Proto__がグラフや文で識別しやすいためです。それ(__Proto__)は標準ではなく、 Object.getProtopeof関数がオブジェクトのプロトタイプを表示する推奨方法であることを覚えておく必要があります。
プロトタイプが特別な理由は何ですか?
私たちはこの質問に答えていません:アレイのプッシュはどこから来たのですか?答えは、MyArrayプロトタイプオブジェクトからのものです。図2は、Chromeのスクリプトデバッガーのスクリーンショットです。 MyArrayのプロトタイプオブジェクトを表示するために、object.getPrototypeofメソッドを呼び出しました。
図2
Codeの例には、Push、Pop、および逆方向のメソッドと呼ばれるものを含む、MyArrayのプロトタイプオブジェクトには多くの方法があることに注意してください。したがって、プッシュ方法にはプロトタイプオブジェクトが含まれますが、MyArrayメソッドはそれをどのように参照しますか?
myarray.push(3);
それがどのように機能するかを理解するための最初のステップは、プロトタイプが特別ではないことを認識することです。プロトタイプは単なる通常のオブジェクトです。メソッド、プロパティをプロトタイプに追加して、他のJavaScriptオブジェクトとして扱うことができます。ただし、ジョージオーウェルの小説「アニマルファーム」に「豚」の声明を適用するには、すべてのオブジェクトは等しくなければなりませんが、一部のオブジェクト(ルールに従う人)は他のオブジェクトよりも平等です。
JavaScriptのプロトタイプオブジェクトは、以下のルールに従うため、実際に特別です。 JavaScriptに、オブジェクトのプッシュメソッドを呼び出すか、オブジェクトのXプロパティを読み取ることを望むとき、ランタイムは最初にオブジェクト自体を探します。ランタイムが必要なものを見つけることができない場合、メンバーを探すために__Proto__リファレンスとオブジェクトのプロトタイプに従います。 MyArrayのプッシュメソッドを呼び出すと、JavaScriptはMyArrayオブジェクトのプッシュメソッドを見つけられず、MyArrayのプロトタイプオブジェクトには、JavaScriptがこのメソッドを呼び出します(図3を参照)。
図3
上記の動作は、プロトタイプの方法またはプロパティを継承するオブジェクト自体を指します。 JavaScriptでは、クラスの構文を使用せずに継承が実際に達成されます。 Racingプロトタイプから対応するテクノロジーを継承する車のように、JavaScriptオブジェクトはプロトタイプオブジェクトから機能的な機能を継承することもできます。
図3は、各配列オブジェクトも独自の状態とメンバーを維持できることを示しています。 MyArrayの長さ属性を要求すると、JavaScriptは、プロトタイプの対応する値を読み取ることなく、MyArrayの長さ属性の値を取得します。オブジェクトへのプッシュなどのメソッドを追加することにより、プッシュメソッドを「上書き」することができます。これにより、プロトタイプのプッシュメソッドの実装が効果的に隠されます。
JavaScriptのプロトタイプの本当の魔法は、複数のオブジェクトが同じプロトタイプオブジェクトへの参照を維持する方法です。たとえば、このような2つの配列を作成する場合:
var myArray = [1、2]; var yourArray = [4、5、6];
次に、これらの2つの配列が同じプロトタイプオブジェクトを共有し、次のコードがtrueに評価されます。
object.getPrototypeof(myArray)=== object.getPrototypeof(YourArray);
2つの配列オブジェクトのプッシュメソッドを参照すると、JavaScriptはプロトタイプで共有されるプッシュメソッドを探します。
図4
JavaScriptのプロトタイプオブジェクトは継承機能を提供し、同時にこのメソッドの共有が実装されます。プロトタイプもチェーンされています。言い換えれば、プロトタイプオブジェクトは単なるオブジェクトであるため、1つのプロトタイプオブジェクトを別のプロトタイプオブジェクトへの参照に維持できます。図2を再検討すると、プロトタイプの__Proto__プロパティが別のプロトタイプを指している非ヌルの価値であることがわかります。 JavaScriptがプッシュメソッドのようなメンバーを探すと、プロトタイプリファレンスチェーンに沿って各オブジェクトが発見されるまで、またはプロトタイプチェーンの終わりに到達します。プロトタイプチェーンは、継承と共有のための柔軟なパスを開きます。
次の質問は次のとおりです。これらのカスタムオブジェクトへのプロトタイプ参照をセットアップするにはどうすればよいですか?たとえば、以前に使用したポイントオブジェクトでは、ADDメソッドをプロトタイプオブジェクトに追加して、複数のポイントオブジェクトからメソッドを継承するにはどうすればよいですか?この質問に答える前に、関数を調べる必要があります。
JavaScriptの関数もオブジェクトです。このような声明はいくつかの重要な結果をもたらし、この記事ではすべての問題をカバーするわけではありません。その中で、機能を変数に割り当て、パラメーターとして別の関数にパラメーターとして渡す機能は、最新のJavaScriptプログラミング式の基本的なパラダイムを構成します。
注意する必要があるのは、関数自体がオブジェクトであるため、関数に独自のメソッド、プロパティ、およびプロトタイプオブジェクトを参照できることです。次のコードの意味について説明しましょう。
// this true:typeof(array)=== "function" //そのような式も:object.getPrototypeof(array)=== object.getPrototypeof(function(){})//そのような式は同じです:array.prototype!= nullコードの最初の行は、JavaScriptの配列が関数であることを証明しています。新しい配列オブジェクトを作成するために配列関数を呼び出す方法を確認します。次のコード行は、配列オブジェクトが他の関数オブジェクトと同じプロトタイプを使用することを証明します。同じプロトタイプが配列オブジェクト間で共有されていることがわかるのと同じように。コードの最後の行は、配列関数がプロトタイププロパティを持っていることを証明し、このプロトタイププロパティは有効なオブジェクトを指しています。このプロトタイププロパティは非常に重要です。
JavaScriptの各関数オブジェクトには、プロトタイププロパティがあります。このプロトタイププロパティの__Proto__属性を混乱さないでください。それらは異なる目的であり、同じオブジェクトを指していることもありません。
// trueObject.getPrototypeof(array)!= array.prototypeを返します
配列.__ Proto__はアレイプロトタイプを提供します。配列関数によって継承されたオブジェクトとして扱ってください。
array.protoypeは、すべての配列にプロトタイプオブジェクトを提供します。つまり、MyArrayのような配列オブジェクトのプロトタイプオブジェクトを提供し、すべての配列が継承するメソッドも含まれています。この事実を証明するためにいくつかのコードを書くことができます。
// truearray.prototype == object.getPrototypeof(myArray)//それはまたtruearray.prototype == object.getPrototypeof(YourArray)です。
また、この新しい知識を使用して、前の図を塗り直すこともできます。
図5
あなたが知っていることに基づいて、新しいオブジェクトを作成し、新しいオブジェクトを配列のように動作させるプロセスを想像してください。 1つの方法は、次のコードを使用することです。
//同じプロトタイプから継承された新しい空のオブジェクトvar o = {}; //配列オブジェクトo .__ proto__ = array.prototype; //配列の任意のメソッドを呼び出すことができます... o.push(3);このコードは興味深いものであり、機能しますが、問題はすべてのJavaScript環境が書き込み可能な__Proto__オブジェクトプロパティをサポートしているわけではないということです。幸いなことに、JavaScriptにはオブジェクトを作成するための標準的なメカニズムがあります。新しいオブジェクトを作成するのは1つの演算子のみであり、新しいオブジェクトの__Proto__リファレンス、つまり「新しい」演算子を設定する必要があります。
var o = new array(); o.push(3);
JavaScriptの新しいオペレーターには、3つの基本的なタスクがあります。まず、新しい空のオブジェクトを作成します。次に、呼び出された関数のプロトタイププロパティと一致するように、新しいオブジェクトの__Proto__プロパティを設定します。最後に、演算子は関数を呼び出し、新しいオブジェクトを「この」参照として渡します。コードの最後の2行を拡張したい場合、それは次の状況になります。
var o = {}; o .__ proto__ = array.prototype; array.call(o); o.push(3);関数の呼び出しメソッドを使用すると、関数を呼び出すときに関数内の「この」で参照されるオブジェクトを指定できます。もちろん、この関数の著者は、この場合にそのような関数を実装する必要があります。著者がそのような関数を作成すると、コンストラクターと呼ばれます。
コンストラクタ
コンストラクターは通常の機能と同じですが、次の2つの特別な特性があります。
配列はコンストラクターの例です。アレイ関数は新しい演算子とともに使用する必要があり、アレイの最初の文字は大文字です。 JavaScriptには組み込み関数としての配列が含まれており、誰でも独自のコンストラクターを書くことができます。実際、以前に作成されたポイントオブジェクトのコンストラクターを最終的に作成できます。
var point = function(x、y){this.x = x; this.y = y; this.add = function(otherpoint){this.x += otherpoint.x; this.y += otherpoint.y; }} var p1 = new Point(3、4); var p2 = new Point(8、6); p1.add(p2);上記のコードでは、新しい演算子とポイント関数を使用して、xおよびy属性とADDメソッドを持つポイントオブジェクトを構築します。図6に示すように、最終結果を想像できます。
図6
問題は、各ポイントオブジェクトにまだ個別の追加メソッドがあることです。学んだプロトタイプと継承を使用して、各ポイントインスタンスからポイントオブジェクトの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 = new point(3、4); var p2 = new point(8、6); p1.add(p2);ミッションは行われます! JavaScriptのプロトタイプの継承モードを完了しました!
図7
要約します
この記事が、JavaScriptプロトタイプの概念の謎を明らかにするのに役立つことを願っています。最初に見たのは、プロトタイプがオブジェクトが他のオブジェクトから機能を継承することを許可し、新しいオペレーターとコンストラクターを組み合わせてオブジェクトを構築する方法を見たことでした。ここで言及されているのは、オブジェクトプロトタイプのパワーと柔軟性を解き放つための最初のステップにすぎません。この記事では、プロトタイプとJavaScript言語に関する新しい情報を自分で発見して学習することを奨励しています。
また、注意深く運転してください。道路を走行するこれらの車両がプロトタイプから継承するような(欠陥のある)テクノロジーを知ることはありません。
オリジナルリンク:スクリプトジャンキー翻訳:Bole Online -Emje