indexOf(NaN)が常に-1を返し、NaNを見つけられない理由
Array.prototype.indexOfは===(厳密等価)で要素を探すため、自分自身とも等しくないNaNを絶対に見つけられません。includes()はSameValueZeroというNaNを特別扱いするアルゴリズムを使うため、NaNも正しく検出できます。
なぜエラーが出ないのか
出力: -1
(エラーなし)- JavaScriptは何も報告しません。文法として正しいためです
出力: -1- 実際の挙動 — 期待した結果と食い違っている箇所
見つけ方- エラーが出ないので、出力を目で確かめるか、コードを目で追うしかありません。この種の誤りが最も発見が遅れます
このエラーが出る典型パターン
パターン1
1 const values = [1, NaN, 3]; 2 console.log(values.indexOf (NaN)); ^
indexOfは===で比較するため、自分自身とも等しくないNaNを絶対に見つけられません。includes()はNaNを特別扱いするSameValueZeroで比較するため正しく検出できます。
直し方: indexOf を includes にします。
パターン2
1 const readings = [12, NaN, 8]; 2 console.log(readings.indexOf (NaN)); ^
配列の途中にあってもindexOfはNaNを見つけられません。includes()を使う必要があります。
直し方: indexOf を includes にします。
パターン3
1 const samples = [NaN, 5, 9]; 2 console.log(samples.indexOf (NaN)); ^
配列の先頭であってもindexOfはNaNを見つけられません。includes()を使う必要があります。
直し方: indexOf を includes にします。
パターン4
1 const data = [7, NaN, 2]; 2 console.log(data.indexOf (NaN)); ^
indexOfは===で比較するためNaNを絶対に見つけられません。includes()を使う必要があります。
直し方: indexOf を includes にします。
パターン5
1 const results = [NaN, NaN, 1]; 2 console.log(results.indexOf (NaN)); ^
先頭に複数あってもindexOfはNaNを見つけられません。includes()なら正しく検出できます。
直し方: indexOf を includes にします。
よくある誤解
「配列に含まれているかを調べるならindexOfでもincludesでも同じはず」という思い込みは、NaNが絡む場面では成り立ちません。NaNの検出だけはincludesでなければ正しく動きません。
実務での勘所
indexOfは===と同じ「厳密等価比較」で要素を探すため、NaNを永遠に見つけられません。includesはSameValueZeroという別のアルゴリズムを使い、これはNaN同士を「同じ」とみなす点でObject.isに似ていますが、+0と-0については区別しないという点でObject.isとは異なります(Object.isは+0と-0を別物として区別します)。MapやSetの内部でのキー比較にも、このSameValueZeroアルゴリズムが使われています。「等価」を表す仕組みがJavaScriptには===・Object.is・SameValueZeroの3種類あり、それぞれ微妙に判定基準が違います。