Code Fix

上級

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));
                            ^
出力: -1期待: true (エラーにはなりません)

indexOfは===で比較するため、自分自身とも等しくないNaNを絶対に見つけられません。includes()はNaNを特別扱いするSameValueZeroで比較するため正しく検出できます。

直し方: indexOf を includes にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  const readings = [12, NaN, 8];
 2  console.log(readings.indexOf    (NaN));
                              ^
出力: -1期待: true (エラーにはなりません)

配列の途中にあってもindexOfはNaNを見つけられません。includes()を使う必要があります。

直し方: indexOf を includes にします。

この問題を解いてみる →

パターン3

 1  const samples = [NaN, 5, 9];
 2  console.log(samples.indexOf    (NaN));
                             ^
出力: -1期待: true (エラーにはなりません)

配列の先頭であってもindexOfはNaNを見つけられません。includes()を使う必要があります。

直し方: indexOf を includes にします。

この問題を解いてみる →

パターン4

 1  const data = [7, NaN, 2];
 2  console.log(data.indexOf    (NaN));
                          ^
出力: -1期待: true (エラーにはなりません)

indexOfは===で比較するためNaNを絶対に見つけられません。includes()を使う必要があります。

直し方: indexOf を includes にします。

この問題を解いてみる →

パターン5

 1  const results = [NaN, NaN, 1];
 2  console.log(results.indexOf    (NaN));
                             ^
出力: -1期待: true (エラーにはなりません)

先頭に複数あっても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種類あり、それぞれ微妙に判定基準が違います。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)