new F()
のように、コンストラクタ関数で新しいオブジェクトを作成できることを思い出してください。
F.prototype
がオブジェクトの場合、new
演算子はそれを使用して新しいオブジェクトの [[Prototype]]
を設定します。
JavaScriptは最初からプロトタイプ継承を備えていました。それは言語の中核機能の1つでした。
しかし、昔はそれに直接アクセスする方法はありませんでした。確実に機能したのは、この章で説明するコンストラクタ関数の "prototype"
プロパティだけでした。そのため、今でもそれを使用するスクリプトがたくさんあります。
ここで F.prototype
は、F
の "prototype"
という名前の通常のプロパティを意味することに注意してください。「プロトタイプ」という用語と似ていますが、ここでは実際にはこの名前の通常のプロパティを意味します。
例を示します
let animal = {
eats: true
};
function Rabbit(name) {
this.name = name;
}
Rabbit.prototype = animal;
let rabbit = new Rabbit("White Rabbit"); // rabbit.__proto__ == animal
alert( rabbit.eats ); // true
Rabbit.prototype = animal
を設定すると、文字通り次のようになります。「new Rabbit
が作成されたら、その [[Prototype]]
を animal
に割り当てます」。
結果の図は次のとおりです
図では、"prototype"
は通常のプロパティを意味する水平矢印であり、[[Prototype]]
は rabbit
が animal
から継承していることを意味する垂直矢印です。
new F
時のみに使用される F.prototype
F.prototype
プロパティは、new F
が呼び出されたときにのみ使用され、新しいオブジェクトの [[Prototype]]
を割り当てます。
作成後に F.prototype
プロパティが変更された場合 (F.prototype = <別のオブジェクト>
)、new F
によって作成された新しいオブジェクトは [[Prototype]]
として別のオブジェクトを持ちますが、既存のオブジェクトは古いオブジェクトを保持します。
デフォルトの F.prototype、constructor プロパティ
すべての関数は、指定しなくても "prototype"
プロパティを持っています。
デフォルトの "prototype"
は、関数自体を指す constructor
プロパティのみを持つオブジェクトです。
このように
function Rabbit() {}
/* default prototype
Rabbit.prototype = { constructor: Rabbit };
*/
確認できます
function Rabbit() {}
// by default:
// Rabbit.prototype = { constructor: Rabbit }
alert( Rabbit.prototype.constructor == Rabbit ); // true
当然のことながら、何もしなければ、constructor
プロパティは [[Prototype]]
を介してすべてのウサギに利用可能です
function Rabbit() {}
// by default:
// Rabbit.prototype = { constructor: Rabbit }
let rabbit = new Rabbit(); // inherits from {constructor: Rabbit}
alert(rabbit.constructor == Rabbit); // true (from prototype)
constructor
プロパティを使用して、既存のものと同じコンストラクタを使用して新しいオブジェクトを作成できます。
このように
function Rabbit(name) {
this.name = name;
alert(name);
}
let rabbit = new Rabbit("White Rabbit");
let rabbit2 = new rabbit.constructor("Black Rabbit");
これは、オブジェクトがあり、どのコンストラクタが使用されたかわからない場合 (たとえば、サードパーティのライブラリからの場合) に、同じ種類の別のオブジェクトを作成する必要がある場合に便利です。
しかし、おそらく "constructor"
について最も重要なことは…
…JavaScript自体が正しい "constructor"
値を保証しないことです。
はい、関数のデフォルトの "prototype"
に存在しますが、それだけです。その後どうなるかは、完全に私たち次第です。
特に、デフォルトのプロトタイプ全体を置き換えると、"constructor"
はなくなります。
例えば
function Rabbit() {}
Rabbit.prototype = {
jumps: true
};
let rabbit = new Rabbit();
alert(rabbit.constructor === Rabbit); // false
そのため、正しい "constructor"
を維持するために、デフォルトの "prototype"
を全体的に上書きするのではなく、プロパティを追加/削除することを選択できます
function Rabbit() {}
// Not overwrite Rabbit.prototype totally
// just add to it
Rabbit.prototype.jumps = true
// the default Rabbit.prototype.constructor is preserved
または、constructor
プロパティを手動で再作成します
Rabbit.prototype = {
jumps: true,
constructor: Rabbit
};
// now constructor is also correct, because we added it
まとめ
この章では、コンストラクタ関数によって作成されたオブジェクトに [[Prototype]]
を設定する方法について簡単に説明しました。後で、それに依存するより高度なプログラミングパターンについて説明します。
すべて非常にシンプルですが、明確にするためにいくつか注意点があります
F.prototype
プロパティ ([[Prototype]]
と間違えないでください) は、new F()
が呼び出されたときに新しいオブジェクトの[[Prototype]]
を設定します。F.prototype
の値は、オブジェクトまたはnull
のいずれかである必要があります。他の値は機能しません。"prototype"
プロパティは、コンストラクタ関数に設定され、new
で呼び出された場合にのみ、このような特殊な効果があります。
通常のオブジェクトでは、prototype
は特別なものではありません
let user = {
name: "John",
prototype: "Bla-bla" // no magic at all
};
デフォルトでは、すべての関数は F.prototype = { constructor: F }
を持っているので、"constructor"
プロパティにアクセスすることでオブジェクトのコンストラクタを取得できます。
コメント
<code>
タグを使用し、複数行の場合は<pre>
タグで囲み、10行を超える場合はサンドボックス (plnkr、jsbin、codepen…) を使用してください。