【问题标题】:Why is isNaN(null) == false in JS?为什么在 JS 中 isNaN(null) == false?
【发布时间】:2010-09-12 01:08:23
【问题描述】:

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

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

我使用的是 Firefox 3。这是浏览器的错误吗?

其他测试:

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

所以,问题似乎不是与 NaN 的精确比较?

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

  • 删除了一条说明我首先通过还原其含义而搞砸了标题
  • 较早的答案表明我没有足够清楚地说明为什么我认为这种行为很奇怪,因此我添加了检查字符串并进行手动比较的示例。

【问题讨论】:

  • 你不是说“为什么 isNaN(null) == false”?
  • 根据您的代码,如果 isnan(null) 显示“我认为 null 是数字”,则返回 false(null 不是“不是数字”)。
  • 改用Number.isNaN

标签: javascript


【解决方案1】:

我相信代码试图问“x 是数字吗?”这里的具体情况是x = null。函数isNaN() 可以用来回答这个问题,但在语义上它专门指的是值NaN。来自维基百科NaN

NaN (Not a Number) 是数字数据类型的值,表示未定义或无法表示的值,尤其是在浮点数中- 点计算。

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

以下是算法解释:

函数isNaN(x) 尝试将传递的参数转换为数字1(相当于Number(x)),然后测试该值是否为NaN。如果参数不能转换为数字,Number(x) 将返回NaN2。因此,如果将参数x 转换为数字导致NaN,则返回true;否则,它返回 false。

所以在特定情况下x = nullnull 被转换为数字 0,(尝试评估 Number(null) 并看到它返回 0,)并且 isNaN(0) 返回 false。只有数字的字符串可以转换为数字,并且 isNaN 也返回 false。无法转换为数字的字符串(例如'abcd')将导致isNaN('abcd') 返回true,特别是因为Number('abcd') 返回NaN

除了这些明显的边缘情况之外,还有返回 NaN (如 0/0)的标准数值原因。

至于问题中显示的看似不一致的相等测试,NaN 的行为被指定为任何比较 x == NaN 为假,无论其他操作数如何,包括 NaN 本身@987654324 @.

【讨论】:

  • 顺便说一句,NaN !== NaN。所以,我认为,说Number('abcd') == NaN 并不完全正确,因为Number('abcd')NaN 但不等于NaN。我喜欢 JavaScript。
  • 是的。我的意思是要传达 Number('abcd')NaN 但我暗示它测试相等性的真实性,但事实并非如此。我会编辑它。
  • null0 的转换仅(至少在这种情况下)发生在 isNaN() 函数中,它强制其参数。
  • Number(null) == 0 但 parseInt(null) == NaN 爱 JS
  • 请注意isNaN(undefined) === true
【解决方案2】:

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

对我来说,isNaN 的最佳使用方式就是这样

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]

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

这对我来说似乎更好。

【讨论】:

  • 如果myInt="123d" 将不起作用。 parseInt 将“123d”转换为 123,然后 isNaN 测试失败。
  • 确实,如果您也想捕捉这种情况,我建议将我的答案和格伦的答案结合起来。看起来像这样isNaN(parseInt(str,10)) || isNaN(Number())。顺便说一句 - 对我来说,因为我必须运行 parseInt 才能使用字符串的数值,所以允许“123d”被视为有效数字就可以了。但是,我认为也需要检测这种情况。
【解决方案3】:

(我的另一条评论采用实用的方法。这是理论上的一面。)

我查了ECMA 262 standard,这是 Javascript 实现的。他们对 isNan 的规范:

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

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

任何在传递给ToNumber 时产生NaN 作为输出的此类输入在馈送到isNaN 时将产生true。由于null可以成功转换为数字,所以不会产生true

这就是原因。

【讨论】:

    【解决方案4】:

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

    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
    

    【讨论】:

    • 你认为 NaN 应该是什么意思?您认为 NaN 或对其进行测试有什么误导性?你为什么不安?
    • 嗯,这是 8 年前的事了,但看起来我很不安 1) 对于非 Number 类型的值,它的结果不一致,2) 它曾经为某事返回 true那不是数字类型。因为字符串实际上不是 NaN。 (另请参阅我的其他答案,这解释了为什么会发生这种情况。)
    【解决方案5】:

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

    【讨论】:

    • 但是至少有一个字符串被转换成一个 NaN 对象,因为 isNaN("text") 返回 true。
    • “isNaN() 只是测试你是否真的有 NaN 对象” — 不,Number.isNaN 这样做。 isNaN 将其参数强制转换为数字,然后检查它是否是 NaN 值。
    【解决方案6】:

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

    并查看The abstract operation ToNumber convertion table。所以它在内部js引擎评估ToNumber(Null)+0,然后最终isNaN(null)false

    【讨论】:

      【解决方案7】:

      我不太确定何时涉及 JS,但我在其他语言中看到过类似的事情,这通常是因为该函数仅检查 null 是否完全等于 NaN(即 null === NaN 将是错误的)。换句话说,它并不是认为 null 实际上是一个数字,而是 null 不是 NaN。这可能是因为两者在 JS 中的表示方式不同,因此它们不会完全相等,就像 9 !== '9' 一样。

      【讨论】:

        【解决方案8】:

        注意:

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

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

        Douglas Crockford's website,雅虎! JavaScript 传道者,是此类内容的绝佳资源。

        【讨论】:

          【解决方案9】:
          (NaN == null) // false
          (NaN != null) // true
          

          虽然很有趣:

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2014-01-10
            • 2015-02-22
            • 2010-12-22
            • 2010-10-23
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多