3

I'm trying to write a simple test for the input of a function to determine if all of the inputs are numbers or not.

function numbers(){
  for (var i = 0; i < arguments.length; i++) {
   if (isNaN(arguments[i])) return false;
  }
  return true;
}

However, when I pass in a list of numbers as characters (eg. numbers("1", "2")) I get true instead of the expected false.

spinlock
  • 3,737
  • 4
  • 35
  • 46
  • Are you passing it strings as opposed to numbers? –  Jan 17 '14 at 03:01
  • 3
    isNaN does not check the type, in simple terms it just sees if it's a number (more specifically, if it's not a number), even if it's a number inside a string. – adeneo Jan 17 '14 at 03:01
  • `isNaN` isn't meant to be used to determine whether or not the argument is a number. It's meant to be used to determine whether or not the argument is a floating-point NaN value. – user2357112 Jan 17 '14 at 03:02
  • @user2357112—where did you get that idea? [ECMA-262](http://ecma-international.org/ecma-262/5.1/#sec-15.1.2.4) says "Returns true if the argument coerces to NaN", e.g. `isNaN(new Date('foo'))` returns true, `isNaN(Infinity)` returns false. – RobG Jan 17 '14 at 03:41
  • @Spinlock—javascript is loosely typed, type checking is frequently counter productive. Better to ensure the correct type only where actually required (e.g. where `+` should perform addition, not concatenation). – RobG Jan 17 '14 at 03:50
  • Use [`Number.isNaN`](//developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN) instead. – Sebastian Simon Jun 30 '21 at 14:39

2 Answers2

4

isNaN implicitly coerces the argument to Number, and then checks whether this coerced value is NaN.
See http://es5.github.io/#x15.1.2.4

That is, isNaN(foo) is equivalent to isNaN(Number(foo))

Code fix:

if (typeof arguments[i] !== 'number' || isNaN(arguments[i])) return false;

The second part of the condition is because typeof NaN === 'number'.


Your function might be a bit more readable in functional style, using ES5's Array#every method:

//returns whether all arguments are of type Number and not NaN
function numbers() {
    return [].every.call(arguments, function(arg) {
        return typeof arg === 'number' && !isNaN(arg);
    });
}
Fabrício Matté
  • 69,329
  • 26
  • 129
  • 166
  • And because `NaN !== NaN` per the [Strict Equality Comparison Algorithm](http://ecma-international.org/ecma-262/5.1/#sec-11.9.6). However it isn't required in order to test for `NaN` as `x !== x` **only** returns `true` if `x` is `NaN` (though it is handy and more expressive). – RobG Jan 17 '14 at 03:34
  • @RobG Yes, thanks for mentioning that `NaN !== NaN`, guess I subconsciously skipped it as anyone who already tried comparing a NaN result with === NaN would know that bit `=]`. The `x !== x` trick is documented in the annotated ES link which I posted as well (though I prefer the `isNaN` function for expressiveness). Thanks for the input. – Fabrício Matté Jan 17 '14 at 04:05
0

isNan() will attempt to cast it to a number, and then check. I would use this instead

if(!isNaN(parseFloat(arguments[i])) && isFinite(arguments[i])){
    return false;
}

Alternatively, if you're using jQuery, you could use its built-in $.isNumeric() function

scrblnrd3
  • 7,228
  • 9
  • 33
  • 64