JavaScriptでnewする、ということ
以下のスクリプトを基本に考える。
function Box(){}
var box=new Box;
Boxはまぎれもなく関数である。正確には関数オブジェクトというらしい(関数もオブジェクトである、という所以か)。コンストラクタですかね。
関数をnewして変数に代入すると、オブジェクトが生成される。それで出来たのがboxだ。通常boxはBoxから派生したのだからBoxで持っていた属性(というかフィールドというか)を引き継ぐ(ここでは何も持っていないので引き継いでいないけれど)。
newして出来たboxはオブジェクトになるわけだが、その際box.__proto__という属性を持つようになる(JavaScript内部でそのような処理が実行されているらしい)。box.__proto__に何が入っているかは後述する。
ここでプロトタイプというものを考える。プロトタイプは関数(ここでいうBox)に対して設定する(オブジェクトboxに設定するものではない)。たとえば上記のスクリプトに追記する。
function Box(){}
Box.prototype.size=1;
var box=new Box;
この状態でbox.sizeは1である。box.sizeは定義も代入もされたことはないけれど1になる。
関数オブジェクトがnewされると、できたオブジェクトに__proto__という属性ができるということは前述した。この__proto__には関数オブジェクトで定義されたプロトタイプ(これもオブジェクトなんだけど)を参照している(ポインタみたいな感じか)。
JavaScriptの仕様で、オブジェクトに特定の属性が存在しない時(ここでいうsize)、当該オブジェクトの属性である__proto__を走査し、sizeという属性を探す。ここでsizeが見つかると、当初のオブジェクトに、いかにもsize属性があるかのごとく、その__proto__.sizeの値を返す。これ、いわゆる継承ってやつですかね。
ちなみに上記のスクリプトで二行目と三行目をひっくり返してみる。
function Box(){}
var box=new Box;
Box.prototype.size=1;
二行目が実行された時点では、box.sizeはundefined。しかし三行目が実行されたらbox.size=1となる。これは__proto__に単純にコピーされたというのではなく参照で渡されているから。元の値が変化すれば、参照している側の値も変化する。
ちょっとわかってきた。