__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は
- this.hoge
- (Child).__proto__.hoge = (Parent).hoge = [Child].prototype.hoge
- (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
期待通りになった。
以上。