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");
の様になる場合は、問題は顕在化しない。