JavaScript 数组含有 NaN,indexOf(NaN) 却返回 -1
indexOf 无法按严格相等规则匹配 NaN。需要索引时使用 findIndex 和 Number.isNaN,只判断存在则使用 includes,并避免把 -1 交给删除操作。
数组里明明有 NaN,查找却没有命中:
const values = [10, NaN, 30];
console.log(values.indexOf(NaN)); // 预期 -1
console.log(NaN === NaN); // 预期 false
标准数组的 indexOf 使用严格相等规则,NaN 与自身也不相等。因此,查找失败不能证明数组没有 NaN。下面针对普通 JavaScript 数组;先区分需要元素位置,还是只需要判断是否存在。
要位置,用 findIndex 配合 Number.isNaN
const values = [10, "bad", undefined, NaN, 30];
const index = values.findIndex(Number.isNaN);
console.log(index); // 预期 3
if (index !== -1) {
console.log(values[index]); // 预期 NaN
}
findIndex 返回第一个符合条件的索引,没有符合项时才返回 -1。Number.isNaN 只接受数值类型的 NaN,不会把字符串和 undefined 转成数字再判断。
不要把这里的回调换成全局 isNaN。它会先做数值转换,例如 isNaN("bad") 为真,可能在真正的 NaN 之前命中一个字符串。两者检查的条件不同。
拿到索引后应显式与 -1 比较。索引 0 是有效位置,if (index) 会漏掉它;而 -1 在布尔条件里反而为真。
只判断存在,用 includes
const values = [10, NaN, 30];
console.log(values.includes(NaN)); // 预期 true
includes 使用的相等规则把两个 NaN 看作相等,因此适合这个判断。但返回值是布尔值,不能直接替代后续还要使用索引的代码。
替换通用查找工具时还要留意稀疏数组:indexOf 跳过缺失元素,includes 将缺失位置当作 undefined。这不影响本例查找 NaN,却可能改变同一工具里查找 undefined 的行为。
如果运行环境没有这些方法,应先确认运行时或现有兼容层。只处理普通数组中的数值 NaN 时,也可以用明确的循环作为局部替代:
function firstNaN(values) {
for (var i = 0; i < values.length; i++) {
if (values[i] !== values[i]) return i;
}
return -1;
}
该判断利用数值 NaN 不等于自身的性质,不会因为字符串无法转换为数字而误报。不要为了这一处查找直接覆盖全局数组原型。
检查首项、缺失项和后续删除操作
在隔离的输入样本上核对 [NaN]、[1, NaN]、[1, 2] 和 ["bad", NaN],首个索引预期分别为 0、1、-1 和 1。如果只判断存在,对应结果应为真、真、假、真。
如果后续会调用 splice 删除元素,必须先排除 -1,否则它会指向数组末尾,可能误删正常数据。查找修正不会恢复已删除的元素;调整前保留原输入,回退时恢复调用逻辑和原数据,不要把失败查找的结果继续用于写入。


