ES6 の Map のコレジャナイ感
YAPC::Asia 2015 Tokyo にて、teppeis さんによる ECMAScript 6 (ES6) についての講演を聞いてきました。ES6 を特に追い掛けていなかった私にとっては、ざっくりとした概略を掴むことができる有意義な内容でした。これまではただただ貧弱という印象だった JavaScript が、ついにそれなりにまともに書けるようになりそうだということで、ES6 の普及が楽しみになりました。
さて、発表の中では新機能の紹介がいくつかあったのですが、そんな中でも、列挙されていただけで紹介はされなかった Map に興味を持ちました。ここで言う Map というのは、Ruby で言うところの Hash
、C++ でいうところの *_map
のような連想配列のことです。
そもそも、JavaScript の Object は連想配列として使えるので、なんで今さら Map を追加するのか、と思う方もいらっしゃるかもしれません。確かにその通りで、大抵の場合は Object で足りるというのも事実です。ただ、Object のキーには String しか使えないという制限があるのです。そのため、たまにある String 以外をキーにしたいという場合には、なんとか文字列表現に落とし込むか (というか勝手に toString
されますが)、Array に格納して O(n) の検索コストを支払うか、頑張って String 以外をキーにできる Map を自分で実装するかのどれかを選ぶ必要がありました。
この String 以外を連想配列に使いたいという若干ニッチな、でも実際にコードを書いていると割と出てくる要望を叶えてくれるのが、ES6 で追加される Map です。これがあれば、文字列表現になることによる扱いにくさを気にする必要も、余計な検索コストを支払う必要も、車輪の再発明を繰り返す必要もありません。
しかもこの機能、ES6 と言っても未来の話ではなく、大体のブラウザの最近のバージョンで利用可能なようです。new Map()
したら普通にインスタンスを作れたのでちょっと驚きました。
まずは普通に文字列をキーにしてみます。
いい感じですね。次は配列を試してみます。
つらい。
Mozilla のドキュメントを読んでみたところ、キーの同一性は “same-value” アルゴリズムに基いていて、===
演算子と同じセマンティクスとのこと。[]
と []
が “same-value” じゃなかったら一体何なんだろうと思いながらも[] === []
を試してみると、確かに false
になります。どうやら、オブジェクトに対して ===
演算子を使うと、同じオブジェクトを参照しているときに等しいとされるようです。
というわけで、以下のようにするとうまくいきます。
個人的には、複数のデータを配列に突っ込んでの group by (Ruby だと array.group_by {|item| [ item.foo, item.bar ] }
みたいな感じ) や、JSON をパースしてできるようなデータのオブジェクトをキーにしてデータを格納するといった用途を想定していたので、そのどちらにも使えそうにないというのは残念でなりません。というか、逆にこの Map はどんなユースケースを想定しているんでしょうか……。