オブジェクトをハッシュテーブルとして使う場合に注意すべき事
javascripter's
gist: 64615 — Gist
をテストしている時に気がついたこと。
最も一般的な
var hashtable = {}; var key = "foo"; if (key in hashtable) { // has key } hashtable[key]; // lookup hashtable[key] = "bar"; // add
は、keyがObject.prototypeに登録されているメンバ名だった時(例えば"hasOwnProperty"や"propertyIsEnumerable")、in演算子がtrueを返して失敗する。
次に、hasOwnPropertyを使ってプロトタイプチェーンを辿らないようにする方法。
var hashtable = {}; var key = "foo"; if (key.hasOwnProperty(key)) { // has key } hashtable[key]; // lookup hashtable[key] = "bar"; // add
これは、hashtableのkeyに"hasOwnProperty"を指定して値を設定した時、次からkey.hasOwnPropertyの部分でエラーになる。よって、
var hashtable = {}; var key = "foo"; if (Object.prototype.hasOwnProperty.call(hashtable, key)) { // has key } hashtable[key] // lookup hashtable[key] = "bar"; // add
とするとよい。
Firefoxは、
var hashtable = {__proto__: null}; var key = "foo"; // 以下一番目と同じ
とするとオブジェクトをハッシュテーブルとして使えるようになるが、Safariだとhashtable["__proto__"]にオブジェクトを再設定すると再びプロトタイプチェーンを辿るようになってしまうので駄目。
これとは別の話で、
var hashtable = {}; function add(key, value) { if (!Object.prototype.hasOwnProperty.call(hashtable, key)) { hashtable[key] = value; } }
とすると、add時にhasOwnPropertyとhashtable[key]の二つでハッシュ値が算出されるので気持ちが悪い。C言語等だとlookupと同時に値を設定できるようにすることも多いらしいのだが(「プログラミング作法」より)、オブジェクトをハッシュテーブルとして使う以上、これは諦めるしかない。