ECMAScript (JavaScript) は「プロトタイプベースの継承」をサポートしています。これは、JS では「クラス」と「インスタンス」の区別がないことを意味します。他の言語の OOP とは対照的に、JS では「クラス」と「インスタンス」は基本的に同じものです。
を定義するBla
と、すぐにインスタンス化されます (すぐに使用できます) がobject Bla
、同じプロパティとメソッドを持つ別のインスタンスの初期 (!) 定義を複製する「プロトタイプ」としても機能します。
ECMAScript では、オブジェクトの初期定義であっても、すべてがオブジェクトです。他の OOP 言語では、定義部分に「クラス」があります。
このオブジェクトは、最初の定義の後prototype
に"Bla" (クラス "Bla" と読みます) のプロトタイプを拡張し、新しいプロパティ/関数を の現在および将来のすべてのインスタンスに追加する場合に使用します。Bla
混乱している場合は、次のコード例が違いを見つけるのに役立つと思います。
// when defining "Bla", the initial definition is copied into the "prototype"
var Bla = function()
{
this.a = 1;
}
// we can either modify the "prototype" of "Bla"
Bla.prototype.b = 2;
// or we can modify the instance of "Bla"
Bla.c = 3;
// now lets experiment with this..
var x = new Bla(); // read: "clone the prototype of 'Bla' into variable 'x'"
console.log(x.b); // logs "2" -- "b" was added to the prototype, available to all instances
console.log(x.c); // undefined -- "c" only exists in the instance "Bla"
console.log(Bla.c); // logs "3" -- "Bla" is an object, just like our new instance 'x'
// also note this:
Bla.a = 1337;
var y = new Bla();
console.log(y.a); // logs "1" -- because the "prototype" was cloned,
// opposed to the current state of object "Bla"
console.log(Bla.a); // logs "1337"
最後の例でわかるように、オブジェクトの現在の「状態」の複製を避けるために「プロトタイプ」の概念が必要です。
このように実装しないと、クローンを作成する前に元のオブジェクト「Bla」が使用/変更された場合、現在の状態もコピーされるため、奇妙な結果になる可能性があります。それが、言語設計者がこの構造を採用した理由prototype
です。
常に覚えておいてください: 「クラス」が他の OOP 言語にあるように、「Bla」は静的な定義ではありません。
ECMAScript 仕様には、次のように記載されていprototype
ます。
プロトタイプは、ECMAScript で構造、状態、および動作の継承を実装するために使用されるオブジェクトです。コンストラクターがオブジェクトを作成すると、そのオブジェクトは、プロパティ参照を解決する目的で、コンストラクターに関連付けられたプロトタイプを暗黙的に参照します。コンストラクターに関連付けられたプロトタイプは、プログラム式 constructor.prototype によって参照できます。オブジェクトのプロトタイプに追加されたプロパティは、継承によって、プロトタイプを共有するすべてのオブジェクトによって共有されます。
同じ名前の「プロトタイプ」のような一部の JS フレームワークは、この機能を多用して Javascript 組み込みオブジェクトの機能を拡張します。
たとえばarray
、メソッドを使用してネイティブ オブジェクトを拡張し、forEach
不足しているこの機能を JS に追加します。
Array.prototype.forEach = function each(iterator, context) {
for (var i = 0, length = this.length >>> 0; i < length; i++) {
if (i in this) iterator.call(context, this[i], i, this);
}
}