prototypeでオブジェクト型プロパティーを定義してはいけない

 function Class(){
 }
 Class.prototype.p1=new Array();

さて上のコードに問題があることがわかるだろうか?

  • JavaScriptではクラス定義の代わりにprototypeを使う。
  • オブジェクトは自信に定義されていないプロパティーはprototypeチェーンをたどって検索し、それを自信に定義されているかのように振る舞う。
  • Array.prototype.push は破壊的動作をする(自分自身を変更する)

つまり

 var instance=new Class();
 var another_instance=new Class();
 instance.p1.push("test");
 alert(another_instance.p1.join(",") ); // ココ

これが期待通りの結果をもたらさないのである。上記コードの3行目で instance.p1に"test"を追加したが、another_instance.p1は変更されていないはずなので join しても空の文字列しか返さないはずだ。なのに another_instance.p1 にも "test" が追加されている!
どうしてこうなるのか。instance.p1 は 実際にはオブジェクト instance1 には定義されていない。従って instance.p1 は、Class.prototype.p1 を参照する。another_instance.p1 も同様である。
見方を変えれば、new Class によって作成されるあらゆるオブジェクトは Class.prototype.p1 を共有するのである。


さて。意図された結果を導きたいのであれば

 function Class(){
  this.p1=new Array();
 }

としなければならない。


もし Array.prototype.push が非破壊的動作をし、つまり「自信のリストの最後に与えられたオブジェクトを追加する」ではなく「自信のリストの最後に、引数を追加した、自信のコピーを返す」という動作をする関数であった場合、つまりコードが

another_instance.p1 = another_instance.p1.push("hoge");

の様になる場合は、問題は顕在化しない。