Comparing NaN values for equality in Javascript
Asked Answered
H

12

79

I need to compare two numeric values for equality in Javascript. The values may be NaN as well. I've come up with this code:

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

which is working fine, but it looks bloated to me. I would like to make it more concise. Any ideas?

Homologate answered 22/1, 2012 at 22:40 Comment(3)
Mixing || and && without some parentheses is extremely ugly and confusing.Psychodiagnostics
NaN and NaN are supposed to be unequal for a reason, because, for example, 0/0 and parseInt("not a number!"), while they both evaluate to NaN, should not be considered equal.Vlaminck
@Peter sometimes this difference is irrelevant to the algorithm. I think this is the case of the OP.Irreparable
S
23

Try using Object.is(), it determines whether two values are the same value. Two values are the same if one of the following holds:

  • both undefined
  • both null
  • both true or both false
  • both strings of the same length with the same characters in the same order
  • both the same object
  • both numbers and
    • both +0
    • both -0
    • both NaN
    • or both non-zero and both not NaN and both have the same value

e.g. Object.is(NaN, NaN) => true

Refer to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is

Spavined answered 17/1, 2018 at 11:48 Comment(2)
Good answer for modern javascript. Just take care because 0 === -0 returns true but Object.is(0, -0) returns false. For the asker's use case you might need to do val1 === val2 || Object.is(val1, val2).Gerius
never knew about this +1. ThanksShorten
P
56
if(val1 == val2 || (isNaN(val1) && isNaN(val2)))

Nothing to improve. Just add the parentheses to make it clear to everyone.

Psychodiagnostics answered 22/1, 2012 at 22:42 Comment(1)
I'd improve it with a comment explaining why should NaN === NaN return true.Hypersonic
S
26

Avoid isNaN. Its behaviour is misleading:

isNaN(undefined) // true

_.isNaN (from Underscore.js) is an elegant function which behaves as expected:

// 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
Shawnshawna answered 22/1, 2012 at 22:54 Comment(8)
undefined becomes NaN when converted to a Number anyway ... imo it's much better to know that during the isNaN phase than after.Hypersonic
What's wrong with isNaN(undefined) being true? undefined isn't a number. What seems to be so misleading here for you?Gaudet
@trejder: NaN and undefined are different values. Different value types, even.Shawnshawna
@davidchambers: True. Which doesn't change the fact, that undefined isn't a number. Which leads us to a conclusion, that isNaN(undefined) should return true. The fact, that NaN and undefined are different values and different value types, doesn't change my state. As this is whole different story. Or point me out, where I'm wrong.Gaudet
@trejder: We have different ideas as to which question isNaN should answer. You believe isNaN(x) should be equivalent to !isNumber(x), whereas I suggest it should tell us whether the value of x is precisely NaN. If one wants to know whether a value is not a number, Object.prototype.toString.call(x) !== '[object Number]' is preferable as it doesn't allow for competing interpretations.Shawnshawna
0/0 and "hello world" are also different value and different value types and both isNaN(0/0) and isNaN("hello world") return true and I can't think of any reason one would want it to be otherwiseIrreparable
@drigoangelo: If you're comfortable writing if (x !== x) and have confidence that all current and future members of your team will understand what that does, great. If not, it would be nice to have a function which answers the question: Is this value NaN? Unfortunately the built-in isNaN is not that function.Shawnshawna
That's why we have references: To know what the meaning of a function is, and not what we guess, it is.Duren
S
23

Try using Object.is(), it determines whether two values are the same value. Two values are the same if one of the following holds:

  • both undefined
  • both null
  • both true or both false
  • both strings of the same length with the same characters in the same order
  • both the same object
  • both numbers and
    • both +0
    • both -0
    • both NaN
    • or both non-zero and both not NaN and both have the same value

e.g. Object.is(NaN, NaN) => true

Refer to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is

Spavined answered 17/1, 2018 at 11:48 Comment(2)
Good answer for modern javascript. Just take care because 0 === -0 returns true but Object.is(0, -0) returns false. For the asker's use case you might need to do val1 === val2 || Object.is(val1, val2).Gerius
never knew about this +1. ThanksShorten
H
5

if ( val1 === val2 )

If either one or both are NaN it will evaluate to false.

Also, NaN !== NaN

Hypersonic answered 22/1, 2012 at 22:43 Comment(1)
Isn't that not equivalent? The OP wanted the expression to return true if both val1 and val2 are NaN.Tapetum
C
5

NaN is never equal to itself no matter the comparison method, so the only more concise solution for your problem that I can think of would be to create a function call with a descriptive name for doing this rather special comparison and use that comparison function in your code instead.

That would also have the advantage of localizing changes to the algorithm the day you decide that undefined should be equal to undefined too.

Composer answered 22/1, 2012 at 22:43 Comment(0)
C
5

As long as you know these two variables are numeric, you can try:

if (val1 + '' == val2 + '')

It turns the two values into strings. A funny answer, but it should work. :)

Constructionist answered 22/1, 2012 at 22:45 Comment(1)
It won't always give an identical result to the original code, but then again, in the cases where it would vary, it may be a preferred behavior. For example " " == 0;, which is true, but will be false with your code. This may be considered an improvement.Overstrung
G
4

And what's about the function Number.isNaN() ? I believe this must be used whenever is possible.

> NaN === NaN
false
> Number.isNaN
ƒ isNaN() { [native code] }
> Number.isNaN() === Number.isNaN()
true

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN

Gyneco answered 16/6, 2015 at 21:29 Comment(1)
Number.isNaN(NaN) === Number.isNaN(undefined) resolves to falseGyneco
O
2

For Numeric cases the solution is fine but to extend it to work for other data-types as well my suggestion would be as follows:

if(val1 === val2 || (val1 !== val1 && val2 !== val2))

Reason being global isNaN is erroneous. It will give you wrong results in scenarios like

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

I have posted a comprehensive answer here which covers the NaN comparison for equality as well.

How to test if a JavaScript variable is NaN

Obtund answered 21/8, 2015 at 10:32 Comment(0)
D
0

An arrow function can 'unbloat' your conditional and I would use Number.isNaN() instead of isNaN() due to the fact that isNaN() will try to convert the value to a number.

const areEqual = (a, b) => a === b || (Number.isNaN(a) && Number.isNaN(b));

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

Using isNaN() might lead to the following problems:

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

Daube answered 5/9, 2023 at 22:59 Comment(0)
M
-1

Why not an if statement like this?

if (isNaN(x) == true){
        alert("This is not a number.");
    }
Molini answered 6/7, 2015 at 17:55 Comment(1)
This does not answer the question.Ideo
C
-1

Equality comparison with NaN always results in False.

We can go for the javascript function isNaN() for checking equality with NaN. Example:

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);
    }
}

Results:

false ---- Values of 0

True ---- Values of 1

Canoness answered 13/4, 2016 at 9:35 Comment(0)
T
-1

Found another way using Array.prototype.includes MDN link. Apparently, [NaN].includes(NaN) returns true for NaN.

function IsActuallyNaN(obj) {
  return [obj].includes(NaN);  
}

Or we can go with davidchambers' solution which is much simpler.

function IsActuallyNaN2(obj) {
  return obj !== obj;
}
Theologize answered 19/5, 2017 at 4:35 Comment(2)
when you write answer on SO always try to give little explanation about your code.Aegina
Don't construct an array literal just for this. If you want to use ES6 methods, use Object.is(obj, NaN)Colloquialism

© 2022 - 2025 — McMap. All rights reserved.