在JavaScript中如何测试NaN?

58

我有一个变量x,我想测试它是否设置为NaN。我该如何做?

我的第一反应可能是,你知道的,像这样进行测试:

if (x === NaN) {  ...

小兔子别傻了,那样太简单了。NaN 就像 SQL 中的 NULL 一样,它不等于任何东西,即使是它自己。

但看,有一个叫做 isNaN() 的函数--也许它可以完成这个任务!

不行,就我所知,isNaN() 完全没用。

例如,isNaN([""]) 正确地返回 false,但是 isNaN(["."]) 返回 true。你不想知道我是怎么发现这个缺陷的。

我该怎么办?

事实证明,我的问题是这个的重复,但是被选中的答案是错误的。正确答案的赞同数只有20%


“你不想知道我是怎么发现这个漏洞的。” - 我想知道为什么你会在一个数组上调用 isNaN - Bergi
1
@Bergi -- 我正在编写一个日期选择器。当["2015", "05", "05"]被标记为NaN时,我几乎要打屏幕了。 - Michael Lorton
但是你为什么期望一个数组像数字一样运作呢? - Bergi
1
@Bergi -- 不是我。Angular 给我的是 NaN,意思是“数据还没有准备好”,而实际的数据(在这种情况下是一个数组)则是准备好了。我需要一种方法来知道数据是否已经准备好。 - Michael Lorton
1
@Bergi--如果你看一下[原来的问题](http://stackoverflow.com/questions/30313950/when-is-render-of-ngmodel-called-with-real-data),你就可以看到问题所在:如果数据没有准备好,Angular会用NaN调用ngModel.$render,如果准备好了,则使用数据。这个数据在某些情况下是一个数组,但还存在许多其他情况。当然,没有理由不将NaN本身视为合法值... - Michael Lorton
显示剩余2条评论
3个回答

75

简短回答

对于 ECMAScript-5 用户:

#1
if(x !== x) {
    console.info('x is NaN.');
}
else {
    console.info('x is NOT a NaN.');
}

对于使用ECMAScript-6的人:

#2
Number.isNaN(x);

为了在 ECMAScript 5 和 6 中保持一致,您还可以使用此Number.isNan 的 polyfill

#3
//Polyfill from MDN
Number.isNaN = Number.isNaN || function(value) {
    return typeof value === "number" && isNaN(value);
}
// Or
Number.isNaN = Number.isNaN || function(value) {     
    return value !== value;
}

注意:我更喜欢使用#1进行测试,它在所有地方都可以正常工作,并且不依赖于最新的JS。(它总是为我提供正确的结果。没有意外!)


详细说明:

这是我们很棒的 NaN

NaN == NaN; // false
NaN === NaN; // false

请不要因此责怪JavaScript,在其他语言中,NaN也应该以这种方式运行,这是可以接受的,正如所有比较返回false NaN值的原理所述。

因此,我们的救星isNaN出现了,但等等,在某些情况下它的行为有点不同。

isNaN(undefined); // true
isNaN({});        // true
isNaN("lorem ipsum"); // true

看到上面的结果我感到有些奇怪。接下来是MDN的解释:

当传给isNaN函数的参数不是Number类型时,该值首先会被强制转换为Number类型。然后测试转换后的值是否为NaN。

那么我们应该如何测试非数字变量的NaN呢? 我通常按照以下方式进行测试:

if(x !== x) {
    console.info('Is a NaN');
}
else {
    console.info('Not a NaN');
}

ECMAScript-6/JavaScript-2015 更新

在 ECMAScript-6 中有没有对应的内容呢?是的,我们有...

Number.isNaN(x); // true

ES6的实现对于上述情况也会有所帮助。

Number.isNaN(undefined); // false
Number.isNaN({}); // false    
Number.isNaN("lorem ipsum"); // false

而 ECMAScript-5 全局函数 isNaN 输出的结果为 true,与我们的预期有时可能不一致。


2
isNaN( "" ) = falseisNaN( {} ) = true 一样,而 Number.isNaN( "" ) = falseNumber.isNaN( {} ) = false - loretoparisi
Polyfill 可以非常简单,例如 Number['isNaN'] || (Number.isNaN = function(a) { return a !== a }); 基本上相同,只是减少了一些字符,并将变量设置移动到运算符的另一侧。 - SpYk3HH
在此处阅读有关 isNaN() 的更多信息:https://www.w3schools.com/jsref/jsref_isnan.asp - Srijan Chaudhary

27

如果你仔细阅读,这个问题就有了答案。这是我找到答案的方式:我正在输入问题,然后...嘿!

还记得我写过"NaN像SQL中的NULL,它与任何东西都不相等,即使是它本身也不行"吗?据我所知,NaN是JavaScript中唯一具有这种属性的值。因此,您可以编写:

var reallyIsNaN = function(x) {
   return x !== x;
};

阅读完MDN Number.NaN文档后,建议同时检查typeof x === "number"isNaN不同之处在于它在比较之前将值强制转换为数字(+[] == 0,wat?) - thgaskell
@thgaskell 当你说 +[] == 0 时,JavaScript 会尝试将数组的第一个值转换为整数。尝试在空数组中调用 array[0],它将返回 undefined。这种转换与 parseInt 不同,undefined 将被转换为 0,尝试 +[1] 和 +['1223fsds']。最后 0 == 0。这就是你得到这个结果的原因。 - devconcept
@thgaskell 是的,我看了那个视频。太搞笑了。看一下这篇帖子:https://dev59.com/y10a5IYBdhLWcg3wboTU#30326359 - devconcept
1
@thgaskell - wat不是wat - Michael Lorton
请保持冷静并记住,Java、C#、Python、Scala、C++(在clang、g++和msvc下)的NaN行为与JavaScript相同。在所有这些语言中,0/0都是NaN,在所有这些语言中,NaN不等于自身。这只是标准要求 - Benjamin Gruenbaum
显示剩余3条评论

0

看起来有点过度,但是怎么样尝试一下呢?

if (Number(dataInput) !== Number(dataInput))
{
    ...
}

1
你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Ethan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接