同じ内容のオブジェクト同士が === でfalseになる理由
オブジェクトや配列の==・===は中身ではなく参照(メモリ上の同一性)を比較します。プロパティの値がすべて同じでも、別々に作られたオブジェクトは等しいと判定されません。
なぜエラーが出ないのか
出力: false
(エラーなし)- JavaScriptは何も報告しません。文法として正しいためです
出力: false- 実際の挙動 — 期待した結果と食い違っている箇所
見つけ方- エラーが出ないので、出力を目で確かめるか、コードを目で追うしかありません。この種の誤りが最も発見が遅れます
このエラーが出る典型パターン
パターン1
1 const a = { id: 1 }; 2 const b = { id: 1 }; 3 console.log(a === b ); ^
オブジェクトの===は中身ではなく参照を比較します。aとbは別々に作られた別のオブジェクトなので、プロパティが同じでも等しくありません。
直し方: a === b を a.id === b.id にします。
パターン2
1 const arr1 = [1, 2, 3]; 2 const arr2 = [1, 2, 3]; 3 console.log(arr1 === arr2 ); ^
配列も参照型なので、要素が全て同じでも別々に作った配列同士は===で等しくなりません。
直し方: arr1 === arr2 を JSON.stringify(arr1) === JSON.stringify(arr2) にします。
パターン3
1 const p1 = { x: 1, y: 2 }; 2 const p2 = { x: 1, y: 2 }; 3 console.log(p1 === p2 ); ^
座標の値が一致していても、p1とp2は別のオブジェクトです。中身を比較したいときはプロパティを個別に比較する必要があります。
直し方: p1 === p2 を p1.x === p2.x && p1.y === p2.y にします。
パターン4
1 const settings1 = { theme: "dark" }; 2 const settings2 = { theme: "dark" }; 3 console.log(settings1 === settings2 ); ^
設定オブジェクトの中身が同じでも、別々に作られたオブジェクト同士は===で等しくなりません。
直し方: settings1 === settings2 を settings1.theme === settings2.theme にします。
パターン5
1 const tags1 = ["a", "b"]; 2 const tags2 = ["a", "b"]; 3 console.log(tags1 === tags2 ); ^
配列も参照型なので、要素が全て同じでも別々の配列同士は===で等しくなりません。
直し方: tags1 === tags2 を JSON.stringify(tags1) === JSON.stringify(tags2) にします。
よくある誤解
「プロパティの値が同じなら等しいはず」という直感は、プリミティブ値(数値・文字列など)には当てはまりますが、オブジェクトには当てはまりません。中身を比較したい場合はプロパティを個別に比較するか、JSON.stringify等で明示的に行う必要があります。
実務での勘所
中身を比較する簡便な方法としてJSON.stringify(a) === JSON.stringify(b)がよく使われますが、これは万能ではありません。プロパティの並び順が違うだけで文字列表現が変わり、実際には同じ内容でもfalseになることがあります。また、関数やundefined、Dateオブジェクトなど、JSONの形式で正しく表現できない値は無視されたり別の形に変換されたりします。厳密な深い比較が必要な場面では、lodashのisEqualのような、この種の落とし穴を考慮して作られたライブラリの関数を使うほうが安全です。
関連するエラー
- スプレッド構文{ ...obj }はネストした値までは複製しない(浅いコピー){ ...obj }や[...arr]は最上位のプロパティだけをコピーします。
- typeof null === 'object' の罠typeof演算子はnullに対して"object"を返します。