オブジェクト指向言語も決して一枚岩でありません。西の横綱もいれば、西の高校生探偵もいます。このブログで扱う事の多いPHP、JavaScriptなどについて見てみますと、PHPはクラスベース言語というタイプに含まれるのに対して、JavaScriptはプロトタイプベース言語というタイプに含まれます。JavaScriptのプロトタイプベース言語の方が、幾分マイナーですので、こちらの特徴を追ってみましょう。
プロトタイプベース言語には、クラスの概念が無い
オブジェクト指向についてかじった事のある人間ならば、あらゆるものがオブジェクトで、そのオブジェクトには設計図たるクラスが必要で…といったようなオブジェクト指向のイロハに馴染んでいることと思います。一方JavaScriptが属するマイノリティ、プロトタイプベース言語には、オブジェクトの設計図たるクラスは存在しません。それでは、オブジェクトは何を元にして作られるのか、何を実体化してインスタンスをつくるのかという疑問が当然沸き上がる筈でしょう。
実は、JavaScriptにおけるインスタンス化は、既存のオブジェクトを丸々コピーすることによって行われます。コピー元もまた実体をもったオブジェクトなのです。
はい、メモリの無駄遣い発見!JavaScriptはとんだ低級言語だぜ!と思われた方は、オブジェクト指向の意義についてしっかりと理解された方だと思います。既存のオブジェクトをコピーするという方法では、もしプロパティやメソッドの実装部分が100個あったら、インスタンスそれぞれにつき100個を丸ごとコピーしなければなりません。それでは、毎度毎度新しいオブジェクトを一から作成しているのと何ら変わりません。そこで、プロトタイプ言語ではそうした問題を解決する方法として、プロトタイプオブジェクトという概念を用意しています。
JavaScriptでのクラス(仮)宣言
JavaScriptでクラスのようなもの、つまりインスタンスにコピーされるコピー元のオブジェクトを宣言する場合には、変数(クラス(仮)名)への関数リテラルの代入だけで済みます。
var Conan = function(){}; |
これで終わりです。右側に書かれた無名関数がコンストラクタになりますので、何かしらプロパティやメソッドを設けたい場合には、function(){}の中に書けば大丈夫です。
var Conan = function(powder){ this.powder = powder; this.pero = function(){ if(this.powder == "青酸カリ"){ alert("これは…青酸カリ!"); } else { alert("この料理を作ったのは誰だっ!"); } }; }; |
これでクラス(仮)Conanにプロパティpowderとメソッドpero()ができました。インスタンスを作成する際に引数を与えることで、プロパティpowderを初期化できます。
var conan = new Conan("青酸カリ"); conan.pero(); //結果 これは…青酸カリ! |
JavaScriptのプロトタイプ
さて、先ほど挙げた問題に戻ります。このままですと、Conanクラスのインスタンスをconan1,conan2,conan3…とどんどん作っていくことで、その都度powderプロパティとpero()メソッドの宣言が行われメモリの無駄になってしまいます。そこで、JavaScriptのクラス(仮)には暗黙のプロパティであるprototypeというものが用意されており、このプロパティ(正体はオブジェクト)への値の代入を行うことで、プロパティやメソッドの追加が行えるようになっています。
var Conan = function(powder){ this.powder = powder; }; Conan.prototype.pero = function(){ if(this.powder == "青酸カリ"){ alert("これは…青酸カリ!"); } else { alert("この料理を作ったのは誰だっ!"); } }; //宣言してもいないConanクラスのプロパティ prototype に値を入れてしまう |
これで、先ほどと同じくインスタンスからメソッドを実行できるようになります。
どの辺りがメモリの節約になったのかと言うと、実はインスタンス側にはpero()メソッドがコピーされておらず、インスタンスからpero()メソッドが呼ばれると、インスタンスの持つprototypeオブジェクトへの参照を便りに、prototypeオブジェクト中の同名メソッドを呼ぶ仕組みになっているのです。
つまりどれだけプロトタイプ側にメソッドやプロパティを追加しても、インスタンス側にはプロトタイプへの参照しか残らないので、経済的だというわけですね。
いかがだったでしょうか。決してJavaScriptの属するプロトタイプベース言語が、クラスベース言語に劣った低級なものでないという事が分かったのではないでしょうか。実はプロトタイプベース言語はクラスベース言語へのアンチテーゼとして作られたという経緯があり、クラスベースのオブジェクト指向の弱点である、開発の段階が進むにつれて設計図であるクラスへの設計図としての要求が高くなってくる(→リファクタリングの必要性が出てくる)といったところをうまく解決して、機能の追加をアドホックに行えるという持ち味を醸しています。
ということで、JavaScriptは案外面白い奴です。
ピンバック: クラスベース言語PHPの基本作法 | AkisiのWEB制作日記