オブジェクトのキーは数値でも文字列に変換される(1と"1"は同じキー)
JavaScriptのオブジェクトのプロパティキーは、Symbolを除きすべて文字列として扱われます。数値のキーを指定しても内部的には文字列に変換されるため、数値の1と文字列の"1"は同じキーとして衝突します。
なぜエラーが出ないのか
出力: 1
(エラーなし)- JavaScriptは何も報告しません。文法として正しいためです
出力: 1- 実際の挙動 — 期待した結果と食い違っている箇所
見つけ方- エラーが出ないので、出力を目で確かめるか、コードを目で追うしかありません。この種の誤りが最も発見が遅れます
このエラーが出る典型パターン
パターン1
1 const votes = {}; 2 votes[1] = "apple"; 3 votes["1"] = "banana"; ^ 4 console.log(Object.keys(votes).length);
votes["1"]はvotes[1]と同じキーを指します。別々の投票のつもりで書いても、片方がもう片方を上書きしてキーは1つのままです。
直し方: "1" を 2 にします。
パターン2
1 const cache = {}; 2 cache[10] = "x"; 3 cache["10"] = "y"; ^ 4 console.log(Object.keys(cache).length);
cache["10"]はcache[10]と同じキーになります。数値と文字列のキーは区別されません。
直し方: "10" を 20 にします。
パターン3
1 const inventory = {}; 2 inventory[100] = "sword"; 3 inventory["100"] = "shield"; ^ 4 console.log(Object.keys(inventory).length);
inventory["100"]はinventory[100]と同一のキーとして扱われ、上書きされてキーは1つのままになります。
直し方: "100" を 200 にします。
パターン4
1 const scores = {}; 2 scores[5] = "A"; 3 scores["5"] = "B"; ^ 4 console.log(Object.keys(scores).length);
scores["5"]はscores[5]と同じキーを指すため、上書きされてキーは1つのままです。
直し方: "5" を 6 にします。
パターン5
1 const map = {}; 2 map[3] = "x"; 3 map["3"] = "y"; ^ 4 console.log(Object.keys(map).length);
数値と文字列のキーは区別されません。map["3"]はmap[3]と同一のキーです。
直し方: "3" を 4 にします。
よくある誤解
「数値のキーと文字列のキーは別物として区別されるはず」という思い込みは誤りです。obj[1]とobj["1"]は同じプロパティを指すため、片方への代入がもう片方の値を上書きします。
実務での勘所
この制約は素のオブジェクトだけの話で、Mapを使えば回避できます。const m = new Map(); m.set(1, ...); m.set("1", ...);のように書くと、Mapは数値の1と文字列の"1"を別々のキーとして正しく区別し、2つのエントリとして保持します。この「キーの型を保持できる」という性質は、ES2015でMapが新しく言語に追加された主な動機の1つです。キーに数値やオブジェクトそのものを使いたい場面では、素のオブジェクトではなくMapを検討する価値があります。