JavaScriptの連想配列(ハッシュ)はArrayオブジェクトでも作成できる!?
- 2009/09/16
橋本章史
こんにちは、橋本です。
今日は、JavaScriptの連想配列(ハッシュ)に関するお話をしたいと思います。
基本的にJavaScriptで連想配列を作るときには、Objectオブジェクトを使用します。
こんな感じ。
キーと値を取るときはこんな感じ。
基本的に配列のキーに文字列を設定することは出来ません。
…と思い込み、今まではこのやり方に特に疑問を感じずにやってきました。
ところが、今日とあるコードにArrayオブジェクトで連想配列を定義している記述が。
「そ、そんな馬鹿な!!ちゃんと動いているはずが…」と思ったのですが、問題なく動いているようで。
ただ、配列のキーに文字列を指定した場合、lengthプロパティには反映されず、alertで配列の中身を表示することも出来ない模様。
これはどういうことなのだろうと思い、いろいろ試してみました。
どうやら配列のキーに数字を指定した場合のみ、配列の値として認識されるようです。
これはなぜか。
結論から言うと、配列のキーに文字列を指定した場合には、配列の要素としてではなく、Arrayオブジェクトのプロパティとして値が定義されます。
つまり、
とやるのは、
とやるのと同じということです。
Objectオブジェクトで連想配列を定義した場合と同様に、プロパティとして定義されるんですね。
ちなみに、ECMAScriptの仕様書を読むと、lengthプロパティのカウントには、内部メソッドのputメソッドを使っているようです。
(参考: Under Translation of ECMA-262 3rd Edition 15.4 Array オブジェクト (Array Objects))
次のように書かれています。
[[Put]] (P, V)
Array オブジェクトは変化した [[Put]] メソッドを用いて他の Native ECMAScript オブジェクトのために使用される。
A を Array オブジェクト、 P を文字列と想定する。
A の [[Put]] メソッドが、プロパティ P と値 V で呼出されるとき、次のステップが取られる:
1. A の [[CanPut]] method を名前 P で呼出す。
2. Result(1) が false ならば、戻る。
3. A 名前 P のプロパティを持たないならば、ステップ 7 へ。
4. P が "length" ならば、ステップ 12 へ。
5. A のプロパティ P を V に設定する。
6. ステップ 8 ヘ。
7. 名前 P のプロパティを生成し、値を V に設定し空の属性を与える。
8. P が配列の添え字でなければ、戻る。
9. ToUint32(P) が A の length プロパティ未満ならば、戻る。
10. A の length プロパティを ToUint32(P)+1 に変更 (または設定) する。
11. 戻る。
12. ToUint32(V) を算出する。
13. Result(12) が ToNumber(V) と等しくなければ、例外 RangeError を投げる。
14. A の length プロパティ の値未満であり Result(12) 未満でない各整数 k について、 A 自身が ToString(k) という名前の (継承したプロパティではない) プロパティを持つならば、そのプロパティを削除する。
15. A のプロパティ P の値を Result(12) に設定する。
16. 戻る。
ざっくり言うと、キーが数字だったらlength変更するけど、そうじゃなかったら、プロパティとして登録するだけって感じみたいですね。
普段PHPを使っていると、JavaScriptの配列でも連想配列を使用することが出来ると思い込みがち。
Arrayオブジェクトを連想配列として使用することも出来ますが、上記のとおり、lengthプロパティに反映されないなど、いろいろ弊害があるかと思います。
ちなみに、さきほど記載した「キー数字&文字列」で作成した配列をfor~in文とlengthプロパティを使用したfor文で表示すると、それぞれ違った結果になります。
紛らわしいので、やっぱり連想配列を使うときには、Objectオブジェクトを使った方がよさげですね。
今日は、JavaScriptの連想配列(ハッシュ)に関するお話をしたいと思います。
基本的にJavaScriptで連想配列を作るときには、Objectオブジェクトを使用します。
こんな感じ。
- var
hoge = { hoge: 'hoge', fuga: 'fuga' - };
キーと値を取るときはこんな感じ。
- for
(var a in hoge) { //キー alert(a); // 値 alert(hoge[a]); - }
基本的に配列のキーに文字列を設定することは出来ません。
…と思い込み、今まではこのやり方に特に疑問を感じずにやってきました。
ところが、今日とあるコードにArrayオブジェクトで連想配列を定義している記述が。
「そ、そんな馬鹿な!!ちゃんと動いているはずが…」と思ったのですが、問題なく動いているようで。
ただ、配列のキーに文字列を指定した場合、lengthプロパティには反映されず、alertで配列の中身を表示することも出来ない模様。
これはどういうことなのだろうと思い、いろいろ試してみました。
- //1.
キー数字のみ - var
hoge = new Array(); - hoge[0]
= 'hoge'; - hoge[1]
= 'fuga'; - alert(hoge.length);
// 2
- //2.
キー文字列のみ - var
hoge = new Array(); - hoge['hoge']
= 'hoge'; - hoge['fuga']
= 'fuga'; - alert(hoge.length);
// 0
- //3.
キー数字&文字列 - var
hoge = new Array(); - hoge['hoge']
= 'hoge'; - hoge['fuga']
= 'fuga'; - hoge[0]
= 'puyo'; - hoge[1]
= 'aaaa'; - alert(hoge.length);
// 2
どうやら配列のキーに数字を指定した場合のみ、配列の値として認識されるようです。
これはなぜか。
結論から言うと、配列のキーに文字列を指定した場合には、配列の要素としてではなく、Arrayオブジェクトのプロパティとして値が定義されます。
つまり、
- var
hoge = new Array(); - hoge['fuga']
= 'hoge';
とやるのは、
- var
hoge = new Array(); - hoge.fuga
= 'hoge';
とやるのと同じということです。
Objectオブジェクトで連想配列を定義した場合と同様に、プロパティとして定義されるんですね。
ちなみに、ECMAScriptの仕様書を読むと、lengthプロパティのカウントには、内部メソッドのputメソッドを使っているようです。
(参考: Under Translation of ECMA-262 3rd Edition 15.4 Array オブジェクト (Array Objects))
次のように書かれています。
[[Put]] (P, V)
Array オブジェクトは変化した [[Put]] メソッドを用いて他の Native ECMAScript オブジェクトのために使用される。
A を Array オブジェクト、 P を文字列と想定する。
A の [[Put]] メソッドが、プロパティ P と値 V で呼出されるとき、次のステップが取られる:
1. A の [[CanPut]] method を名前 P で呼出す。
2. Result(1) が false ならば、戻る。
3. A 名前 P のプロパティを持たないならば、ステップ 7 へ。
4. P が "length" ならば、ステップ 12 へ。
5. A のプロパティ P を V に設定する。
6. ステップ 8 ヘ。
7. 名前 P のプロパティを生成し、値を V に設定し空の属性を与える。
8. P が配列の添え字でなければ、戻る。
9. ToUint32(P) が A の length プロパティ未満ならば、戻る。
10. A の length プロパティを ToUint32(P)+1 に変更 (または設定) する。
11. 戻る。
12. ToUint32(V) を算出する。
13. Result(12) が ToNumber(V) と等しくなければ、例外 RangeError を投げる。
14. A の length プロパティ の値未満であり Result(12) 未満でない各整数 k について、 A 自身が ToString(k) という名前の (継承したプロパティではない) プロパティを持つならば、そのプロパティを削除する。
15. A のプロパティ P の値を Result(12) に設定する。
16. 戻る。
ざっくり言うと、キーが数字だったらlength変更するけど、そうじゃなかったら、プロパティとして登録するだけって感じみたいですね。
普段PHPを使っていると、JavaScriptの配列でも連想配列を使用することが出来ると思い込みがち。
Arrayオブジェクトを連想配列として使用することも出来ますが、上記のとおり、lengthプロパティに反映されないなど、いろいろ弊害があるかと思います。
ちなみに、さきほど記載した「キー数字&文字列」で作成した配列をfor~in文とlengthプロパティを使用したfor文で表示すると、それぞれ違った結果になります。
- var
hoge = new Array(); - hoge['hoge']
= 'hoge'; - hoge['fuga']
= 'fuga'; - hoge[0]
= 'puyo'; - hoge[1]
= 'aaaa'; - //
for~in文 - for
(var i in hoge) { alert(hoge[i]); //'hoge','fuga','puyo','aaaa'が表示される - }
- //
lengthプロパティを使用したfor文 - for
(var i = 0; i < hoge.length; i++) { alert(hoge[i]); //'puyo','aaaa'が表示される - }
紛らわしいので、やっぱり連想配列を使うときには、Objectオブジェクトを使った方がよさげですね。
コメントフォーム
トラックバック
-
- JavaScript Object from JustOnePlanet Blog
- ■オブジェクトを生成 オブジェクトリテラルを使った生成 世間的には...
2009年09月19日 05:43
最近の記事
- sshでポートフォワード [2010年09月06日 : 門脇優児]
- もうすぐ健康診断があるんだ・・・ [2010年09月02日 : 阿部恵]
- Photoshopで壁紙を作りながら、基本的な使い方を覚える [2010年09月01日 : 鴨田健次]
- はじめての共同作業 Canvas編 (node.js + websocket) [2010年09月01日 : 中川善樹]
- 「PHP×Flex(後編)」PHPテクニカルセミナー(無料)第4弾の募集を開始しました!! [2010年08月26日 : 和田記光]
- 【HTML5】Canvasでお絵かきしてみた(前編) [2010年08月25日 : 橋本章史]
- MacにgroongaのMySQL用ストレージエンジン [2010年08月23日 : 笹亀弘]
- Appleのサイトで見たiPhone4をFireworksで描いてみました-1/2 [2010年08月19日 : 和田記光]
- iPad版の会社紹介を作ってみました [2010年08月19日 : 小林有佳]
- iPhoneアプリ開発開始時に気をつけるべきファイルの取り扱い (2) [2010年08月19日 : 亀本大地]



最近のコメント