JavaScriptがプロトタイプ(prototype)ベースのオブジェクト指向言語と言われて、クラスベースのオブジェクト指向言語(例:Java、C++など)にないプロトタイプの概念を理解するには少し時間がかかった。JavaScriptの中級以上になると、プロトタイプを理解して、JavaScriptらしくコーティングしたほうがいいと思う。
もちろん、プロトタイプを利用してコーティングするに一長一短があるので、プロトタイプの概念を無視して、関数とオブジェクトを理解した上てコーティングすることもできる。むしろプロトタイプの概念を利用せずコーティングしたプログラムの可読性が高く、一般的な開発者に合わせやすいかもしれない。
ここで、JavaScriptの関数、オブジェクトを理解したうえ、プロトタイプの複雑な参照関係を省いて、その基本的な概念、利用ルールを調査してまとめた。それを習得すればよりJavaScriptらしくコーティングができるようにすれば良いと思いう。
オブジェクトがそのオブジェクトコンストラクタにある(prototype)を参照する
- 生成されたオブジェクトにプロトタイプ・プロパティを持っていない
- コンストラクタ関数が定義したときに、プロトタイプが自動的に作成される
- 生成されたオブジェクトがそれを生成するコンストラクタにあるプロトタイプ・プロパティへの参照を行う
- 参照リンク「__proto__」がブラウザのタイプ、バージョンより実装していないものもあり、このリンクがなくても暗黙な参照関係がある
オブジェクトでプロトタイプ(prototype)にあるプロパティ値が変更された場合にそのプロパティがコピーされる
- プロトタイプの値がオブジェクト生成後に変わらない場合そのオブジェクトにコピーせず、参照されるだけになる。
- プロトタイプの値がオブジェクト生成後に変更された場合そのオブジェクトにコピーされ、コンストラクタから切り離される。
- この動きがクラスベースオブジェクト指向言語にある継承した親クラスにあるメッソド、変数のオーバーライドに似ている。
プロトタイプが親オブジェクトのプロトタイプへの参照(プロトタイプチェン:prototype chain)
- オブジェクトのプロパティが存在しない場合、自分のコンストラクタ、親のコンストラクタのプロトタイプを参照しに行くことがプロトタイプ・チェンと言う
- プロトタイプがObjectタイプなので、その最上位までのオブジェクトのコンストラクタに参照を行う
プロトタイプの使用のメリットはメモリの節約とオブジェクトのプロパティ値を一括変更にある
- 上記例でも説明したコンストラクタの値を生成されたオブジェクトから変えない限り、このプロパティが参照され、オブジェクトにコピーされない ⇒ メモリの節約
function Human(){ } ;
Human.prototype.name = "Mac" ;
var person_1 = new Human() ; // オブジェクト生成
var person_2 = new Human() ; // オブジェクト生成
console.log ( person_1.name ) ; // Mac と表示され
console.log ( person_2.name ) ; // Mac と表示され
person_2.name = "Tiffany" ; // プロパティ値変更
console.log ( person_2.hasOwnProperty( "name" ) ); // true <-プロパティがコピーされた
console.log ( person_1.hasOwnProperty( "name" ) ); // false <-プロパティが参照のみ
- プロトタイプにある値、関数を変えれば、生成されたすべのオブジェクトのプロパティを一括変更となる(このプロパティの値を生成されたオブジェクト内で変更せず、コピーされていない前提)
function Human(){ } ;
Human.prototype.name = "Mac" ;
var person_1 = new Human() ; // オブジェクト生成
var person_2 = new Human() ; // オブジェクト生成
// プロトタイプで一括変更
Human.prototype.name = "Tiffany" // プロトタイプの値変更
// 一括変更された結果の確認
console.log ( person_1.name ) ; // Tiffany と表示され
console.log ( person_2.name ) ; // Tiffany と表示され
// プロパティの値が変更されたら、一括変更ができなくなる
person_2.name = "Coco" ; // オブジェクトのプロパティ値変更
// 再度プロトタイプで一括変更
Human.prototype.name = "Jone" ;
// 変更結果の確認:参照のプロパティのみが変更された
console.log ( person_2.name ); // Coco <-プロパティがコピーされた
console.log ( person_1.name ); // Jone <-プロパティが参照のみ
プロトタイプの利用は慎重にしたほうがいいと思う
- プロトタイプでオブジェクトのプロパティ管理にはメモリの節約、一括変更のメリットがある
- プロトタイプでオブジェクトのプロパティ管理には柔軟性が高いが、開発規模が大きくなると、プロパティのどこで定義して、どこて変えられたかを特定するのは難しくなる
- 最初からプロトタイプの利用を計画してルールを決めるべき、コーティング中にルールに従う必要がある