为什么在 JS 中 isNaN (null) = = false?

JS 中的这段代码给了我一个弹出窗口,说“我认为 null 是一个数字”,我发现这有点令人不安。我错过了什么?

if (isNaN(null)) {
alert("null is not a number");
} else {
alert("i think null is a number");
}

我用的是火狐3,是浏览器漏洞吗?

其他测试:

console.log(null == NaN);   // false
console.log(isNaN("text")); // true
console.log(NaN == "text"); // false

那么,问题似乎不是与 NaN 的精确比较?

编辑: 现在这个问题已经得到了回答,我已经清理了我的文章,以便为档案馆提供一个更好的版本。然而,这使得一些评论,甚至一些答案有点难以理解。不要责怪他们的作者。我改变的事情包括:

  • 删掉了一张纸条,上面写着我一开始就把标题的意思颠倒了
  • 早期的答案表明,我没有足够清楚地说明为什么我认为这种行为很奇怪,所以我添加了检查字符串并进行手动比较的示例。
63041 次浏览

Null 不是 NaN,字符串也不是 NaN。IsNaN ()只是测试您是否真的拥有 NaN 对象。

我不是很确定它是否适用于 JS,但我在其他语言中看到过类似的情况,这通常是因为函数只检查 null 是否与 NaN 完全相等(即 null = = NaN 将为 false)。换句话说,并不是它认为 null 实际上是一个数字,而是 null 不是 NaN。这可能是因为两者在 JS 中的表示方式不同,所以它们不会完全相等,就像9一样!= =’9’。

我相信密码是想问“ x是数字吗?”这里的 x = null的特殊情况。函数 isNaN()可以用来回答这个问题,但是从语义上讲,它特别指的是值 NaN。来自 Wikipedia for NaN:

NaN (Not Nnumber)是数值数据类型的值,表示未定义或不可表示的值,特别是在浮点计算中。

在大多数情况下,我们认为“是空数字吗?”应该是不。但是,isNaN(null) == false在语义上是正确的,因为 null不是 NaN

下面是算法解释:

函数 isNaN(x)尝试将传递的参数转换为数字 < a href = “ https://developer.mozilla.org/en/JavaScript/Reference/Global _ Objects/isNaN”rel = “ noReferrer”> 1 (相当于 Number(x)) ,然后测试该值是否为 NaN。如果参数不能转换为数字,Number(x)将返回 NaN一个 href = “ https://developer.mozilla.org/en/JavaScript/Reference/Global _ Objects/Number”rel = “ noReferrer”> 2 。因此,如果将参数 x转换为数字导致 NaN,则返回 true; 否则返回 false。

因此,在特定的情况下,null被转换为数字0(尝试计算 Number(null)并查看它返回0) ,而 isNaN(0)返回 false。只有数字的字符串可以转换为数字,isNaN 也返回 false。无法转换为数字的字符串(例如 'abcd')将导致 isNaN('abcd')返回 true,特别是因为 Number('abcd')返回 NaN

除了这些明显的边缘情况是返回 NaN 的标准数值原因,如0/0。

对于问题中显示的似乎不一致的相等性测试,指定了 NaN的行为,使得任何比较 x == NaN都是假的,而不管其他操作数,包括 NaN本身 < a href = “ https://developer.mozilla.org/en/JavaScript/Reference/Global _ Objects/isNaN”rel = “ noReferrer”> 1

这确实令人不安。下面是我测试过的一组值:

var x = [undefined, NaN, 'blah', 0/0, null, 0, '0', 1, 1/0, -1/0, Number(5)]

它的计算结果(在 Firebug 控制台中)为:

,NaN,blah,NaN,,0,0,1,Infinity,-Infinity,5

当我调用 x.map(isNaN)(在每个值上调用 isNaN)时,我得到:

true,true,true,true,false,false,false,false,false,false,false

总之,isNaN看起来相当没用!(剪辑: 除了结果是 isNaN 只是 定义除以 Number,在这种情况下它工作得很好——只是使用了一个具有误导性的名称。)

顺便说一下,下面是这些值的类型:

x.map(function(n){return typeof n})
-> undefined,number,string,number,object,number,string,number,number,number,number

(我的另一个评论采取了实际的方法,这里是理论方面。)

我查了一下 ECMA 262标准,它是 Javascript 实现的:

将 ToNumber 应用于其参数,然后如果结果为 NaN 则返回 true,否则返回 false。

第9.3节指定了 ToNumber的行为(它不是一个可调用的函数,而是类型转换系统的一个组件)。为了总结表,某些输入类型可以生成 NaN。它们是类型 undefined,类型 number(但只有值 NaN) ,任何基元表示为 NaN的对象,以及任何无法解析的 string。这样就剩下了 undefinedNaNnew Number(NaN)和大多数字符串。

任何这样的输入,当传递给 ToNumber时产生 NaN作为输出,当馈送给 isNaN时将产生 true。因为 null可以成功地转换成一个数字,所以它不会产生 true

这就是为什么。

注:

"1" == 1 // true
"1" === 1 // false

= = 运算符进行类型转换,而 = = = 不进行类型转换。

道格拉斯·克罗克福特的网站 是一个雅虎的 JavaScript 布道者,是一个很好的类似资源。

我自己也碰到了这个问题。

对我来说,使用 NaN 的最好方法是这样的

isNaN(parseInt(myInt))

以 Phyzome 为例,

var x = [undefined, NaN,     'blah', 0/0,  null, 0,     '0',   1,     1/0, -1/0,  Number(5)]
x.map( function(n){ return isNaN(parseInt(n))})
[true,      true,    true,   true, true, false, false, false, true, true, false]

(我根据输入对齐了结果,希望它更容易阅读。)

我觉得这样更好。

在 ES5中,如果参数强制执行 NaN,则定义为 isNaN (number)返回 true,否则返回 false。

  • 如果 编号(号码)为 NaN,则返回 true。
  • 否则,返回假。

看看 抽象操作 ToNumber 转换表,所以内部 js 引擎计算 ToNumber(Null)+0,最终 isNaN(null)false

(NaN == null) // false
(NaN != null) // true

有趣的是:

(NaN == true)  // false
(NaN == false) // false
(NaN)          // false
(!NaN)         // true

(NaN == false)(!NaN)不是一样的吗?