そうそう。JavaScript の配列は扱いにくいんですよ。

JavaScript の暗黒面を覗く

というか Hash として活用しようとすると途端に扱いにくくなるって感じかな。確かに中身はハッシュテーブルかもしれないけど、Hash としては扱いにくい。けっきょく全部 for ( in ) でなめます、みたいな感じで書かざるを得ない。ださい。length プロパティもそうだけど他にもいくつかメソッドが期待したようには動作しない。少なくとも Firefox では。

で、どうせなら has_value() とか keys() とかほしいなと思ったので、自分は試しに Hash オブジェクトを作ってみた。すると JavaScript のオブジェクト周りの扱いにくさというかクセがよく分かる。

Object はプロパティの集合体でありハッシュテーブルなので、Object を作ってそこに obj[key] = val って放り込んでいくだけで Hash でござい、と言えてしまう。でも前述のように便利メソッドがないので Function を使ってオブジェクトを作って、そこにメソッドを足してみる。するとメソッドも変数と同じなので for ( in ) したときにそのまま列挙されてしまう1。そうか、じゃあ列挙するのはもうみんな中のメソッドでやることにして、if ( typeof key != 'function' ) とかやればいいんだ、と思って調子に乗ってメソッドを作って行く。するとハッシュキーに使える名前がどんどん減っていく2。それも困る。

そこでオレHash はこういう作りにしてみた。

var Hash = new funtcion() {
  return function() {
    this.obj = {};
  }
}
Hash.prototype = {
  method: function() {
  },
  ...
}

つまり実際のデータは hash.obj の中に詰め込んでいく。こうするとメソッドとデータの key で名前がぶつかることはない。しかしこの方法だと hash[key] = val とか for ( in ) とか普通の構文が一切使えなくなる。そこでずいぶん悩んだが、「ええいそんなもん禁止だ!」と開き直って Ruby からアイディアを拝借して fetch() とか store() とか merge() とかバンバン作っていく。そうするとなんとかそれっぽく使える状態になる。

ハッシュの中に Array を作るときは

hash.store( key, [] );
hash.fetch( key ).push( val );

てな感じ。まぁ正直これもどうだって感じではあるけど、練習にはいい題材だったと思う。

  1. ユーザーの定義したプロパティには DontEnum 属性がセットできないんだよな。 

  2. やってみれば分かるが、prototype.js の Hash では "keys" という名前のプロパティに値を代入すると keys() メソッドが壊れる。ところで prototype.js って prototype を使わないでプロパティをコピーして回ってるように見えるんだけど、これも富豪アプローチですか? 

More