個人でWebサイトやアプリ、ゲームを作っています(屋号は sesebox です)。
次に作るゲームの準備で、物語のアイデアを10テーマに分けて集めて、1枚のHTMLページで見られるようにしました。上にテーマのボタンを並べて、押すと絞り込める、というよくある形です。
スマホで開いてみたら、ボタンの並びがこうなっていました。
すべて / そのほか / 抜け出す / 掃除・片付け / 壊す・掘る / …
「そのほか」は10番目のテーマなので、本当はいちばん最後に来るはずです。なのに先頭に来ていました。
(2026年11月時点、Node.js と Chrome で試した内容です)
書いていたコード
テーマは、番号をキーにしたオブジェクトで持っていました。
const THEMES = {
"01": "抜け出す",
"02": "掃除・片付け",
// …
"09": "守る・見張る",
"10": "そのほか",
};
for (const [key, label] of Object.entries(THEMES)) {
// ボタンを作って並べる
}
書いた順に "01" → "10" と並ぶと思っていました。
実際の並び順
Node.js で確かめると、こうなります。
const T = { "01": "a", "02": "b", "10": "c" };
console.log(Object.keys(T));
// [ '10', '01', '02' ]
"10" だけが先頭に来ています。
理由:「整数っぽいキー」は先に、小さい順に並ぶ
JavaScript のオブジェクトのキーの並び順には、決まりがあります。
-
整数として読めるキー(
"1"、"2"、"10"など)が、数の小さい順に先に並ぶ - そのあとに、それ以外の文字列のキーが、入れた順に並ぶ
ここでの「整数として読める」は、「数字に直して、また文字列に戻したときに、元と同じになる」という意味です。
| キー | 整数として読める? | 理由 |
|---|---|---|
"10" |
⭕ | 10 → "10" で元と同じ |
"01" |
❌ | 1 → "1" になってしまい、元の "01" と違う |
"x" |
❌ | 数字ではない |
"01" から "09" は頭に 0 が付いているので、ふつうの文字列あつかいになります。"10" だけが整数あつかいになって、先頭に移動していました。
試しに混ぜてみると、ルールがよく分かります。
const U = { "1": "a", "2": "b", "10": "c", "x": "d", "01": "e" };
console.log(Object.keys(U));
// [ '1', '2', '10', 'x', '01' ]
整数として読める "1" "2" "10" が小さい順に先に並び、そのあと "x" "01" が入れた順に並んでいます。
直し方:順番が大事なものは配列で持つ
並び順に意味があるデータは、オブジェクトではなく配列で持つのが確実です。配列は入れた順番がそのまま保たれます。
const THEME_LIST = [
["01", "抜け出す"],
["02", "掃除・片付け"],
// …
["10", "そのほか"],
];
// 並べるときは配列をそのまま回す
for (const [key, label] of THEME_LIST) {
// ボタンを作って並べる
}
// 番号から名前を引きたいときだけ、オブジェクトに変換して使う
const THEMES = Object.fromEntries(THEME_LIST);
⚠️ Object.fromEntries でオブジェクトに戻すと、そのオブジェクトの並びはまた「10」が先頭になります。並べるときは必ず配列のほうを回します。
console.log(Object.keys(Object.fromEntries([["01", "a"], ["10", "c"]])));
// [ '10', '01' ]
ほかにも、キーを "t01" のように数字で始まらない形にする方法や、Map を使う方法もあります。Map も入れた順番を保ちます。
まとめ
- オブジェクトのキーは、整数として読めるものが先に、小さい順に並ぶ
-
"01"は整数あつかいにならないので、"10"だけ先頭に飛ぶ - 並び順が大事なら、配列か Map で持つ
番号を "01" のように0で埋めておけば並ぶと思い込んでいたので、10個目を作ったところで初めて気づきました。9個までは問題なく並んでしまうので、気づきにくいところです。