素人がプログラミングを勉強していたブログ

プログラミング、セキュリティ、英語、Webなどのブログ since 2008

連絡先: twitter: @javascripter にどうぞ。

オブジェクトをハッシュテーブルとして使う場合に注意すべき事


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と同時に値を設定できるようにすることも多いらしいのだが(「プログラミング作法」より)、オブジェクトをハッシュテーブルとして使う以上、これは諦めるしかない。