JavaScriptのprototypeプロパティに対する理解

prototypeに対する理解を深めるために少し考えてみた

var obj = {};
var func = function(){};

alert(obj.prototype); //undefinedと出力
alert(func.prototype); //[object Object]と出力


まずprototypeプロパティを出力してみる。obj(普通のObject)の場合、undefinedと出力される。つまりprototypeというプロパティ自体もっていない。これに対してfunc(普通のfunction)の場合、prototypeはObjectになる。ここで、prototypeに指定されたオブジェクトはプロトタイプオブジェクトと深い関わりがある。順を追って説明する。

JavaScriptにはプロトタイプチェーンという仕組みがある。このプロトタイプチェーンの仕組みは全てのオブジェクトで使える。例えばあるオブジェクトのプロパティを参照しようとした場合、そのオブジェクトにそのプロパティが無ければ、今度はプロトタイプオブジェクトとして指定されたオブジェクトに、そのプロパティを参照しにいく。ここでもそのプロパティが無ければ、さらにプロトタイプオブジェクトを辿っていくという仕組みである。

ここで注意したいのは、prototypeプロパティで指定されたオブジェクトが、そのままprototypeプロパティを定義しているオブジェクトのプロトタイプオブジェクトになるわけではない。これは下のコードを実行してみると分かる。

var objB ={x:30};
var objA = {};
objA.prototype = objB;

alert(objA.x); //undefined

ここではobjAのprototypeプロパティにobjBを指定している。もし、objAのプロトタイプオブジェクトがobjBなら、アラートの部分で、objBの持つxプロパティにアクセスできるはずである。しかし実際はこの方法では参照できない。これは関数オブジェクト(関数もオブジェクトの一種である)の場合も全く同じ。

var funcB = function(){};
funcB.x = 30;
var funcA = {};
funcA.prototype = funcB;

alert(funcA.x); //undefined

ではどうすれば、プロトタイプオブジェクトを指定できるのだろうか?ここで重要になってくるのが、newキーワードである。newは関数をコンストラクタとみなして、そこから新しいオブジェクトを生成するためのキーワードである。JavaScriptではnewキーワードの後ろに関数名を書くことで、指定した関数の持つ、prototypeプロパティの参照するオブジェクトを、新たに生成するオブジェクトのプロトタイプオブジェクトにすることができる。以下のようなコードを実行すると、正しくxの値が参照できる。

var func = function(){};
func.prototype.x = 30;

var test = new func();
alert(test.x); //30

newキーワードが有効なのは関数だけである。普通のオブジェクトに対して、newキーワードを使うことはできない。

var obj ={};
obj.prototype = {}; //もともとundefinedだったのでオブジェクトを指定する
obj.prototype.x = 30;

var test = new obj(); //もちろんこんなことはできない

そもそもobjには最初からprototypeプロパティが無かったのだが、これは普通のオブジェクトにprototypeプロパティがあっても意味がないからだ。prototypeプロパティは、newキーワードを使って新しいオブジェクトを生成するときにしか利用されない。

追記 2010/2/18

id:nanto_viさんに指摘をしていただき、一部修正しました。id:nanto_viさん、ありがとうございました。