__proto__とprototypeについて

Kanasan.jsで__proto__とprototypeの関連について調べる
っていう宿題があったのを思い出し、
調べてみたので以下解説。


オブジェクトの特徴として、
・全てのオブジェクトは__proto__プロパティを持ちます。
そして
・全ての関数オブジェクトはprototypeプロパティを持ちます。

またnewによって作成されたオブジェクトの
__proto__プロパティにはその関数のprototypeがセットされ
__proto__はconstructorプロパティを持ちます。
このconstructorプロパティはnewした関数オブジェクトを指しています。



では次にコード的に見ていきましょう。
以下のような関数(クラス)Parent,Childがあったとします。

function Parent() { }

function Child() { }
Child.prototype = new Parent();

単純な継承関係ですね。
そしてChildクラスからオブジェクトを作成します。

var myobj = new Child();

ここまでの動作で役者としては4個のオブジェクトが登場します。

  • Parent関数オブジェクト
  • Parentをnewしたオブジェクト
  • Child関数オブジェクト
  • Childをnewしたオブジェクト


オブジェクトを()で囲みその中に関数名(クラス名)、
関数オブジェクトを[]で囲みその中に関数名で表示という表記で、
上記のコードの関係を書き出してみます。
=は代入ではなく、右辺のオブジェクトと等しいと読み替えてください。

(?).constructor = [Parent]
[Parent].prototype = (?)
(Parent).__proto__ = [Parent].prototype = (?)

[Child].prototype = (Parent)
(Child).__proto__ = [Child].prototype = (Parent)
(Child).__proto__.constructor = [Child]
(Child).constructor = 'undefined'

という関係が成り立ちます。


追記:画像にしてみました。


そしてprototypeチェーンとは、
プロパティの参照時に辿っていく連鎖の事で
上記の場合、(Child)のプロパティhoge

  1. this.hoge
  2. (Child).__proto__.hoge = (Parent).hoge = [Child].prototype.hoge
  3. (Child).__proto__.__proto__.hoge = (Parent).__proto__.hoge = (?).hoge

の順に探していきます。(= は全て同じものを指している)
(?)については多重に継承している場合は、同様に__proto__で繋がっていきます。
継承が終わった時点で(?)はnullになります。
プロパティの参照時、(?)がnullの場合そのプロパティはundefinedという値になります。



とまぁ、ここまでが調べた答え。


そして実際に動作の確認。(FireFox2.0を利用)

var Parent = function(){}
var Child = function(){}
Child.prototype = new Parent();

alert(new Child().__proto__ === Child.prototype);   # trueとなる

うん。調べた通りだ。
次に少しいじわるをしてprototypeにnullを突っ込んでみた。

Child.prototype = null;

alert(Child.prototype === null);   # true
alert(new Child().__proto__ === null); # false
alert(new Child().__proto__ === Child.prototype); # false

あれ・・??
てっきり__proto__にはnullが入って
チェーンが繋がらないものと思ったけど。
2つ目と3つ目の結果からnullではないんだ。

調べるとどうやら、コンストラクタで
prototypeから__proto__へ値をセットする時、
prototypeがオブジェクトでなければObject.prototypeを
セットするという仕様らしい。

alert(new Child().__proto__ === Object.prototype); # true

期待通りになった。

以上。