Code Tips‎ > ‎

JavaScriptの連想配列は配列じゃないよ

PHPやVBなどでは「連想配列」は「配列」としての性質も持ちます。しかしJavaScriptでは「配列」と「連想配列」は明確に違います。混同して使用すると大変な目にあうこともあります。必ず区別して使いましょう。

連想配列として使用したときのlength

例えばこのサンプル。
var list = [];
list["AKB"] = "秋葉原";
console.log(list["AKB"]);
実行すると「秋葉原」と表示されます。…期待通りに配列を連想配列として扱えているかのように見えます。

ですが
console.log(list.length);
とすると配列に格納されている項目は0件だと評価されます。おそらく配列だと思っている使用者の期待は1件となってほしいのではないかと思います。しかし実際には連想配列に1件、配列には0件なので上記の結果になります。lengthは配列の長さを取得するためのメソッドで、連想配列の長さは取得できないからです。

Array.concatを使う

次にこのサンプル。
var listA = [];
listA[0] = "秋葉原";
listA[1] = "栄";

var listB = [];
listB[0] = "ジャカルタ";
listB[1] = "上海";

var listC = listA.concat(listB);
console.log(listC[0]);
console.log(listC[2]);
console.log(listC.length);

2つの配列を結合して新しい配列を生成しています。結果はこうなります。これは期待通りです。
秋葉原
ジャカルタ
4

これを、連想配列を使用した内容に書き換えます。
var listA = [];
listA["AKB"] = "秋葉原";
listA["SKE"] = "栄";

var listB = [];
listB["JKT"] = "ジャカルタ";
listB["SNH"] = "上海";

var listC = listA.concat(listB);
console.log(listC["AKB"]);
console.log(listC["JKT"]);
console.log(listC.length);

実行すると以下の結果になります。
undefined
undefined
0
listAとListBは配列部分は空ですから、concatした結果は空の配列になってしまうためこうなります。


配列でfor-inを使うのもダメよ

その他、配列に対しfor-inを使うことも間違っています。Arrayが拡張されていない状況でなら配列でfor-inを使っても期待通りに動きます。ですので拡張しなければいいじゃないかという意見は一見正しいように思えます。しかし予期せず拡張されてしまうケースも発生しえます。私が経験したのは、特定のPCでIEでアクセスしたときにエラーが出てしまうという現象です。

コードを見ると連想配列として使おうとしているのに、配列で宣言していました。そこに違和感を感じたものの、配列として使用している記述はないため一応それでも動きそうな内容でした。実際大多数のPCでは問題なく動いていました。

不具合が発生するPCでIEの「開発者ツール」で調べると、Arrayに本来存在しないメソッドが拡張されていることが確認できました。さらに調べると、あるプラグインがインストールされていると、内部でArrayが拡張されるということが分かりました。そのプラグインは一時的に流行ったアドウェアだったこともあり、それを悪者にしてそいつを駆除するという対策が顧客に通知されました。しかし、Arrayが拡張されたら正しく動かなくなるプログラムというのも問題だったので、あとで連想配列なのに配列宣言をしている部分も修正することになりました。

上記のケースはレアケースではありますが、そもそも正しいコードを書いていれば発生しなかった問題です。無用なトラブルを避けるためにも連想配列として扱いたいのに変数を配列で宣言するのはやめたほうがいいでしょう。


余談

私が昔参考にしたことがあるサイトを含め複数のサイトで、「JavaScriptで配列は、連想配列としても使用できる」などと書いてある記事がありました。それを読んで勉強した人は連想配列は配列の仲間だと誤認し、間違ったコードを書いてしまう可能性があるのでしょう。

ネットの情報は妄信せずに、複数の情報ソースを確認した上で利用するようにしましょうね。


2014/10/22