handlename's blog

コード片など

JSでprototypeで宣言したプロパティに値を代入するときの罠

要点

prototypeは、そのオブジェクトに該当のプロパティが存在しない場合に参照される。

どういうこと?

JSでクラスをつくる場合、デフォルト値としてprototypeに値を入れることがある。

var Hoge = function() {};
Hoge.prototype.huga = 0;
Hoge.prototype.piyo = { x: 0, y: 10 };

var hoge = new Hoge();

// hogeにはhugaというプロパティが無いので、
// Hoge.prototype.hugaが参照される。
console.log(hoge.huga); // => 0

// こちらも同様
console.log(hoge.piyo.x); // => 0;

1段階なら問題ないが、2段階以上オブジェクトをたどる場合は要注意。

hoge.huga = 1;     // hogeにhugaというプロパティがつくられて、そこに代入される。
hoge.piyo.x = 100; // Hoge.property.xに代入される。

つまり、こういうこと。

  1. hogeのpiyoプロパティを探す
  2. 見つからないのでHogeのprototypeから探す
  3. prototypeにpiyoが見つかったので、そこからxを探す
  4. Hoge.prototype.piyo.xに100を代入する

Hoge.prototypeの値が直接書き換えられてしまう。

var hoge2 = new Hoge();

// prototypeが書き変わっているので、デフォルト値が変わっている。
console.log(hoge2.piyo.x) // => 100;

となってしまう。

これを防ぐためには、例えば次のようにする。

var piyo = { x: hoge.piyo.x, y: hoge.piyo.y };
piyo.x = 100;
hoge.piyo = piyo;

こうすればhogeに新しくpiyoというプロパティがつくられて、それに対して代入が行われるので、2回目以降のnewに影響することはない。