Object.prototype 汚染に関してObjectを親に持たないオブジェクト

__prpto__ に null を代入すればObjectを親に持たないオブジェクトが作成できる。

問題の所在

以前書いたエントリーの通り、Object.prototype に便利関数を入れるとどんなオブジェクトに対しても使えるようになって便利なんだけどハッシュとして使用する場合に不便です。

Object.prototype.extend = function(....){
 ....
}

var hash = { a:"a", b:"b" }

for( var i in hash ){
  document.writeln( "hash["+ i + "]=" +hash[i] );
}
//↑
// a=a
// b=b
// extend = function(...) ... ←こんなのいらない!

JavaScriptにおいて、すべてのオブジェクトはObjectオブジェクトを親に持ちます。ですから、Objectのprototypeに何かを追加するとすべてのオブジェクトがそのプロパティーを持ってしまうことになるのです。

最速インターフェース研究所の人が書いているとおり、そのプロパティーが、自身が持っているものかプロトタイプとなったオブジェクトで設定されたものかは、hasOwnProperty メソッドで調べることができます。

//↑上の例の続き

hash.hasOwnProperty( "a" ); // true
hash.hasOwnProperty( "extend" ); // false

ですから、オブジェクトをハッシュとして使用する場合次のようにすればなんとかなります。

for( var i in hash ){
  if( hash.hasOwnProperty(i) ) this[i] = hash[i];
}

しかし面倒くさい! あと、常にそれを気にしないといけないので、

if( hash[property] ) alert(hash[property])

のような単純な式で行けるところも

if( hash.hasOwnProperty(property) && hash[property] ) alert(hash[property])

のようにしないといけません。

今回の解決

で、
檜山正幸のキマイラ飼育記 - プログラマのためのJavaScript (8):オブジェクト生成の仕組み
http://d.hatena.ne.jp/m-hiyama/20050909/1126235062
を見て思いついたのですが、純粋にハッシュとして使用するのであれば、生成したオブジェクトのプロトタイプチェーンをぶった切ってやれば、なんかそれっぽいオブジェクトができるようです。

Object.prototype.test="a";

var a = {b:"b"};
a.__proto__ = null; //←ぶった切る

for(i in a){
  print(i+"="+a[i]+"\n");
}

こんな感じ。

当然 Objectが本来持っているメソッド hasOwnProperty なども使えなくなり、「すべてのオブジェクトはこの処理ができるはず!」と、その種のメソッドを使っている処理は破綻します。あと、処理系依存になってしまうのが痛いところ(__proto__プロパティーECMAScript規格で決められたものではない)。

とはいえ、これでObjectプロパティーの汚染をいちいち考えなくてすむかもしれません。

ハッシュクラスというものを考えてみました。

function Hash(original){
  for( var i in original ){
    if( original.hasOwnProperty(i) ) this[i] = original[i];
  }
}
Hash.prototype.__proto__ = null;

//このように使う↓
var h = new Hash({a:"a"});

メソッドを追加できないのであまり便利ではない…orz 素直に hash.__proto__=null したほうが便利かも。…まあ。

というか

というかそもそも Object.prototype にいろんなものをぶち込まないでください。prototype.jsはそれだけで使う気が…
( object ).extend(...) などとなっているところを Object.extend( object, .... ) と書き直す方向でお願いします…