StoryEdit 開発日誌

ウェブアプリ StoryEditを作ってましたが延期。普通のブログ。

JSのプロトタイプについて実装から考える(雑記)

プロトタイプベース,クラスベースの話がいろいろ溢れているので,つれづれなるままに書いてみる。随筆なので、結論はかいているうちにでてくることを祈る。

まず、「JSにはクラスがない。かわりにプロトタイプベースのクラスを作る。」ってのが、一般的な解釈。実装から話すことが一番の理解であるため、実装ベースで考えてみる。ちなみに,どちらの言語も実装したことはないし,ソースも読んでないので,自分の理解のメモ.

(以下,断定的に書いているが,現在の自分の理解であって,真実ではない可能性を含む)

そもそもクラスとはなにか。クラスとは、複数のデータと手続きを持たせたオブジェクトを精製する為のひな形だ。もともと、複数のデータを持たせる、構造体が発展した物だ。構造体は、データサイズ毎に、コンパイラがアクセス先をかえることで、実現される。

struct human {
  int age;
  char[16] name;
};

struct human h = {3, "John"};
h.age; // <= hの指す先の、0番目を参照
h.name; // <= hの指す先の、age分(intのサイズ分)先を参照

では、これがクラスになると、どうなるか。 基本的には構造体とおなじ。しかし、メソッドはメインストリーム言語ならば、変更されることがないためその関数へのポインタを持つ。newされたときに、これらは焼き込まれ、必要最低限の容量を持ったオブジェクトが生成される。

フィールドへのアクセサも、そのフィールドへのgetter, setterをクラステーブルテーブルにしてもたせるかどうか、そのようにコンパイルするかしないかで実装可能だろう。フィールドをダイナミックに変更できないのは、これらのオフセットが静的に決まっている為であり、メリットはダイレクトアクセスができるので、速度が早くなる。

では、動的に変更させるにはどうするか。それはアクセスの度に、該当するフィールドのオフセットを計算できればよい。メソッドの追加も、クラステーブルをメモリ内部に持たせて、その場でアクセスさせればよいだけだ。これで、動的に動作するクラスベースの仕組みは作れる。変更がない限り、オフセットはキャッシュさせるなりで、ダイレクトアクセスに近い速度がでるだろう。
これをさらにリッチに(メモリ的な意味で)したかったら、ハッシュにすることだ。毎回毎回計算するため、ダイレクトアクセスは使えないが、いくらでも増やせるため動的な動きを付加できるだろう。

では,プロトタイプベースとはなにか.そもそもJSは言語的に根本的な実装が違う.JSは,フィールドアクセス(ドットをつかったオブジェクトからサブオブジェクトへのアクセス)をサポートしているが,このとき,オブジェクトには,名前 - サブオブジェクトを管理するためのハッシュがひとつ組み込まれている.(これをフィールドハッシュと呼ぼう)

このため,JSはドットアクセスをハッシュ探索にきりかえるだけだ.そして,プロトタイプとは,フィールドハッシュにある特殊な値のことをさす.それがprototypeなるフィールドだ.
prototypeフィールドは,値としてハッシュを持ち,JSは自身のフィールドにそのキーが見つからなかった場合は,さらにprototypeを探索するようにできている.

  Hoge = function () {};
  Hoge.prototype.fieldX = 3;
  obj = new Hoge();
  print obj.fieldX; // 3と表示される

繰り返すが,JSは自身のフィールドハッシュに指定されている名前がない場合は,このprototypeというフィールドをさらに探索する,という仕掛けをもっているだけである.このため,上の4行目は,自身のフィールドハッシュに"fieldX"がないから,本来は'undefined'を返すところだが,prototypeを持っているため,こちらまで探索して,ようやく"fieldX"を発見する,というわけだ.

おもしろいのは,prototypeの内部に,さらにprototypeがあれば,そちらまで参照すること.これはプロトタイプチェーンと呼ばれるらしく,これによって,クラス継承のようなことが実現できる.

つまり,プロトタイプベースのクラスとは,このprototypeをうまく使って,クラスからオブジェクトを作るようにJSでもクラスを定義しましょうよ.というお話なのだ.
JSにクラスがあるか,ないかの議論は,言語の実装から考えれば,クラスシステムを言語がサポートしていない,という意味で,「仕様としてはない」が正解だろう.では,プロトタイプベースのクラスがあるか?という質問は,これも「ない」である.あくまで,「JSで,OOPしたいなら、プロトタイプってのがあるから、それを使ってね。」というのが正解だろう.

次は,newって何ぞ?的な話を考察したい.