JavaScript中比较NaN值的相等性

76

我需要在Javascript中比较两个数值是否相等。这些值可能是NaN

我想到了以下代码:

if (val1 == val2 || isNaN(val1) && isNaN(val2)) ...

代码目前可以正常运行,但我觉得它太臃肿了。我想让它更简洁。有什么建议吗?


8
在没有加括号的情况下混合使用 ||&& 是非常丑陋和令人困惑的。 - ThiefMaster
12
NaNNaN 应该被认为是不相等的,因为例如 0/0parseInt("not a number!") 虽然它们两个都求值为 NaN,但不应被视为相等。 - Peter Olson
2
@Peter 有时这种差异对算法来说是无关紧要的。我认为这是 OP 的情况。 - drigoangelo
12个回答

54
if(val1 == val2 || (isNaN(val1) && isNaN(val2)))

没有需要改进的地方。只需添加括号以使它对每个人更加清晰明了。


9
我会加上一条注释来解释为什么 NaN === NaN 应该返回 true。 - Esailija

26

避免使用isNaN,它的行为是具有误导性的:

isNaN(undefined) // true

_.isNaN(来自Underscore.js)是一个优雅的函数,其行为符合预期:

// Is the given value `NaN`?
// 
// `NaN` is the only value for which `===` is not reflexive.
_.isNaN = function(obj) {
  return obj !== obj;
};

_.isNaN(undefined) // false
_.isNaN(0/0) // true

10
isNaN(undefined) 返回 true 有什么问题吗?因为 undefined 不是数字。你觉得这里有什么会让人误解的地方? - trejder
7
@trejder: NaN和undefined是不同的值。即使是不同的值类型 - davidchambers
5
@davidchambers:没错。但这并不改变undefined不是数字的事实。这导致我们得出结论,isNaN(undefined)应该返回trueNaNundefined是不同的值和不同的类型,这个事实并不改变我的论点。因为这是完全不同的故事。如果我有错的话,请指出来。 - trejder
5
@trejder:我们对于 isNaN 应该回答哪个问题有不同的看法。你认为 isNaN(x) 应该等价于 !isNumber(x),而我建议它应该告诉我们 x 的值是否确切为 NaN。如果想知道一个值是否不是数字,最好使用 Object.prototype.toString.call(x) !== '[object Number]',因为它不允许竞争性解释。 - davidchambers
2
@drigoangelo:如果你习惯于编写 if (x !== x) 并且有信心所有当前和未来的团队成员都能理解它的作用,那太好了。如果不是,那么最好有一个函数来回答这个问题:这个值是否为 NaN? 不幸的是,内置的 isNaN 函数并不是那个函数。 - davidchambers
显示剩余3条评论

23

尝试使用Object.is(),它确定两个值是否为相同的值。如果满足以下条件之一,则两个值是相同的:

  • 都是undefined
  • 都是null
  • 都是true或都是false
  • 都是长度相同、字符顺序相同的字符串
  • 都是相同的对象
  • 都是数字,并且
    • 都是+0
    • 都是-0
    • 都是NaN
    • 或者都是非零并且都不是NaN,并且都具有相同的值

例如:Object.is(NaN, NaN) => true

请参阅https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is


现代JavaScript的好答案。只需小心,因为0 === -0返回true,但Object.is(0, -0)返回false。对于提问者的用例,您可能需要执行val1 === val2 || Object.is(val1, val2) - Michael Kropat
以前不知道这个+1。谢谢。 - pariola

5

if (val1 === val2)

如果其中一个或两个都是 NaN,它将被解释为假。

此外,NaN !== NaN


这不是等价的吗?OP希望表达式在val1和val2都为NaN时返回true。 - Adam Parkin

5

无论比较方法如何,NaN永远不等于自身,因此我能想到的唯一更简洁的解决方案是创建一个具有描述性名称的函数调用,用于执行这种非常特殊的比较,并在代码中使用该比较函数。

这也会有一个优点,即当您决定未定义应该等于未定义时,可以将更改局部化到算法。


5
只要您知道这两个变量是数字,您可以尝试以下操作:
if (val1 + '' == val2 + '')

它会将这两个值转换为字符串。虽然有点幽默,但应该是有效的。 :)

1
它不会总是给出与原始代码完全相同的结果,但在那些可能会有所不同的情况下,这可能是一种更可取的行为。例如 " " == 0;,这是 true,但在您的代码中将是 false。这可能被认为是一种改进。 - user1106925

4

Number.isNaN(NaN) === Number.isNaN(undefined) 的结果为 false。 - mario ruiz

2
对于数字情况,这个解决方案很好,但是为了将其扩展到其他数据类型,我的建议如下:
if(val1 === val2 || (val1 !== val1 && val2 !== val2))

原因是全局的isNaN有误。在某些情况下,它会给出错误的结果,例如:

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

我在这里发布了一份全面的答案,其中还涵盖了NaN相等性的比较。

如何测试JavaScript变量是否为NaN


0
箭头函数可以简化你的条件语句,我会使用Number.isNaN()而不是isNaN(),因为isNaN()会尝试将值转换为数字。
const areEqual = (a, b) => a === b || (Number.isNaN(a) && Number.isNaN(b));

if (areEqual(val1, val2)) {...}

使用isNaN()可能会导致以下问题:
let val1 = 'a string';
let val2 = undefined;
let val3 = {};
isNaN(val1) && isNaN(val2) && isNaN(val3); // true
Number.isNaN(val1) && Number.isNaN(val2) && Number.isNaN(val3); // false

isNaN(1n); // Uncaught TypeError: Cannot convert a BigInt value to a number
Number.isNaN(1n); // false

Number.isNaN() - JavaScript | MDN


-1

NaN与任何值的比较结果都为False

我们可以使用JavaScript函数isNaN()来检查NaN的相等性。 例如:

1. isNaN(123) //false

2. var array = [3, NaN];

for(var i = 0 ; i< array.length; i++){
  if(isNaN(array[i])){
      console.log("True ---- Values of " + i);
    } else {
      console.log("false ---- Values of " + i);
    }
}

结果:

假 ---- 值为0

真 ---- 值为1


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