「バグを調査している途中で、実はかなり危ないことに気づいた」
「なんだい?」
「ネット上のJavaScriptの連想配列の説明が間違っている例が多すぎる」
「間違った例を教えてくれ」
「以下は典型的なよくある間違ったバターンだ」
配列の場合 §
var x = new Array();// またはvar x =[];
x[0] = "b";
x[1] = "d";
alert(x[0]);
alert(x[1]);
連想配列の場合 §
var x = new Array();// またはvar x =[];
x["a"] = "b";
x["c"] = "d";
alert(x["a"]);
alert(x["c"]);
「何が良くないわけ?」
「x["a"] = "b";っていうのは任意のオブジェクトに動的にメンバーを追加しているだけなんだ。そして、配列オブジェクトもオブジェクトだからメンバーを追加できている。しかし、それは配列にメンバーを追加したこととはイコールにならない」
「なぜそれが問題になるわけ?」
「サイズを取得したら一発で分かる。alert(x.length);を追加してみよう」
「あっ! 配列の場合は2になるのに連想配列の場合は0になる」
「そうだ。実はJavaScriptには本当の意味での連想配列は無いんだ。みんなが連想配列と言っているのは、オブジェクトに対する動的なメンバーの追加削除に過ぎない。つまり、配列オブジェクトを使ったとしても、配列としての機能と一切関係無く、動的にメンバーが追加されたり削除されていたりするだけなのだ」
「じゃあ、配列の意味ないじゃん」
「そうだ。だから初期化の際に new Array();や[]を指定するのはまったくの無駄」
「じゃあどう書けばいいの?」
「空のオブジェクトとして{}を書けば良いだけだ」
var x = {};
x["a"] = "b";
x["c"] = "d";
alert(x["a"]);
alert(x["c"]);
「だけどさ、こうしたらlengthが使えなくなっちゃったよ」
「それは配列のメンバーだから当たり前だ。ここではもう配列を使っていないんだ」
「じゃあどうやってサイズを得るわけ?」
「for inでまわして数を取得するしかなかろう」
var length=0;
for (var dummy in x) length++;
alert(length);
「でもさ。配列ならサイズが取得できて当たり前じゃん。これは配列の一種といえるの?」
「言えないよ。だから本当の意味での連想配列はJavaScriptには無いんだよ。連想配列的に使える機能があるだけ」
「じゃあ話を簡単にするためには配列のlength使うのやめて、全部for inで数えていい?」
「それはダメっ! 動的に追加されたメンバーも数えちゃうから本当の配列の個数とは違う数値が出てくる場合があるのっ!」
「ほんとに?」
「以下のように書くと配列のサイズは2だけど、for inループは3回まわっちゃうの!」
var x = [];
x[0] = "b";
x[1] = "d";
x.hello = function () { alert("hello!"); };
var length=0;
for (var i in x) length++;
alert(length);
「素直にalert(x.length);と書けば2が出てくるわけだね」
「それからこういう例もあるからね」
var x = [];
x[0] = "b";
x[2] = "d";
var length=0;
for (var i in x) length++;
alert(length);
alert(x.length);
「あれ、for inは2回しかまわらないのに、x.lengthは3を報告するぞ」
「そうだ。オブジェクトに入っているデータは2個しかないが、添え字は0から2まで存在しているからだ」
感想 §
「泥沼に足を取られた」
「なんで?」
「うっかりネットから取ってきたサンプルソースを改変して書いたらドはまりした」
「分かった。どこにも存在しない【JavaScriptの連想配列】を当てにして扱ってしまったんだね」
「そうだな。ネットの情報嘘ばかりだ」
「日頃からそう言ってる君がはまっていたら世話が無いよ」