constructorとprototype.constructorがわからなくなった

constructor(プロパティ)とprototype.constructor(プロパティ)は
別物だと思っていたけど、やっぱり同じ物だとおもいつつもやっぱり違うのか?と
よくわからなくなってきた。(特に継承とかしようとした場合に)
ので少し調べてみた。
(ちなみにSpiderMonkeyをつかって試している)

constructorプロパティとは

サイ本によると、

オブジェクトの初期化で使用されたコンストラクタ関数を参照する。

とある。

var a = new Array();
a.constructor == Array;//>trueになる

確かに、Arrayオブジェクトでnewした変数aのconstructorプロパティは
Arrayになっているようだ。

じゃあ、Arrayのconstructorプロパティってなんだろ?

これで気になったのは、newしてないArrayオブジェクトのconstructor
プロパティはなんだろう?
それはFunctionオブジェクト。はて?

自作したオブジェクトで考えるとわかりやすいかも

自作で用意したHogeオブジェクトは

function Hoge(x){
  this.x = x;
}

と定義する。
HogeのconstructorプロパティもFunctionだ。
これは、書き換えると

var Hoge = new Function("x", "this.x = x");

とも書ける。Arrayオブジェクトのように組み込みオブジェクトは見えないけど
Functionオブジェクトをnewして作られているんだなと考えるとイメージしやすい。
(ただしこの2つは微妙に違いがあるようなのであくまでも考え方です)

続いてprototype.constructorプロパティ

その前にprototypeプロパティとは

関数が定義されたときに自動的に生成される。初期値はconstructor
プロパティのみのオブジェクトのこと。

prototype.constructorプロパティとは

コンストラクタ関数自信を参照する。

ということで、みてみよう。先ほどのHogeオブジェクトでみてみる

Hoge.prototype.constructor == Hoge; //>true

確かにコンストラクタ関数と同じだ。

さあ、こんがらがっていこうか!

ここで問題。
Hogeオブジェクトをnewしてできた変数hoge
prototype.constructorプロパティはなにか?
なんかHogeっぽくも思える。
でも、

var hoge = new Hoge("hoge");
hoge.prototype.constructor == Hoge;

の結果はhoge.prototypeにそんなプロパティはないよって怒られる。
正解はエラーになる。ですな。
さらに、prototypeプロパティはundefinedになってる。

なーんでか?

先ほどのprototypeプロパティとはで書いた定義をよく見ると、

関数が定義されたときに自動的に生成される。

とある。
変数hogeは関数として定義したわけでないからprototypeプロパティはないわけだ。

見えてきた?2つのconstructorプロパティの関係

ということで、最初のconstructorプロパティと
prototype.constructorプロパティは別か同じかという疑問の答えは
別物とあっさりでてしまった。
そして、不思議なことに、
Hogeオブジェクトとそのオブジェクトから作られたhogeを比較すると、

hoge.constructor == Hoge.prototype.constructor; //>true

と同じものになる。さらに

Hoge.constructor == Function.prototype.constructor; //>true

も同じになる。
newされて生成された変数(インスタンス)のconstructorプロパティは
コンストラクタ関数のprototype.constructorプロパティが設定されてるって
考えられるんだ。
なんだか、脈々と受け継がれている関係がみえてきたような。