15

MY code is:

function isNumber(n){
return typeof n == 'number' && !isNaN(n);
}

window.onload=function(){
var a=0,b=1,c=2.2,d=-3,e=-4.4,f=10/3;
var shouldBeTrue=[a,b,c,d,e,f];

var aa="0",bb="1",cc="2.2",dd="-3",ee="-4.4",ff="10/3";
var shouldBeFalse=[aa,bb,cc,dd,ee,ff];

var aaa,bbb=true,ccc=false,ddd=document.getElementsByTagName('html');
var alsoTheseBeFalse=[aaa,bbb,ccc,ddd,""," ",,null,NaN];

for(var i=0;i<shouldBeTrue.length;i++)
    if(isNumber(shouldBeTrue[i]) != true) alert("x");
for(i=0;i<shouldBeFalse.length;i++)
    if(isNumber(shouldBeFalse[i]) != false) alert("x");
for(i=0;i<alsoTheseBeFalse.length;i++)
    if(isNumber(alsoTheseBeFalse[i]) != false) alert("x");
}

What else should I check against to ensure my function is 101% perfect in all ways? (also, if you know a better function please tell me)

Rob W
  • 341,306
  • 83
  • 791
  • 678
  • 1
    which function are you looking to make perfect? You could start by giving your variables more meaningful names... – frenchie Dec 15 '11 at 20:15
  • @frenchie: He's talking about the `isNumber(n)` function. – Cᴏʀʏ Dec 15 '11 at 20:18
  • There were numeric cases you didn't check, but I cant make your function break (ie: g=2E30, gg=0/0) – Brian Dec 15 '11 at 20:19
  • @Brian, well 0/0=NaN (and I did check for that), but I am curious about the '2E30' thing because it returns true. Do you know why it returns true? –  Dec 15 '11 at 20:24
  • 1
    Side note, inside your test cases, you're using `!= false`. This is not needed, because your `isNumber` function always return a boolean (`true` or `false`). Within `if ( ... )`, an expressions is always treathed as a boolean. `if (isNumber(a) != false)` is equivalent to `if (isNumber(a) == true)` is equivalent to `if (isNumber(a))`. – Rob W Dec 15 '11 at 20:47

6 Answers6

23

If you want to check whether a number is a real number, you should also check whether it's finite:

function isNumber(n){
    return typeof n == 'number' && !isNaN(n) && isFinite(n);
 }

Another method (explanation below):

function isNumber(n){
    return typeof n == 'number' && !isNaN(n - n);
}

Update: Two expressions to validate a real number

Since JavaScript numbers are representing real numbers, the substraction operand on the same number should produce the zero value (additive identity). Numbers out of range should (and will) be invalid, NaN.

1        - 1        = 0    // OK
Infinity - Infinity = NaN  // Expected
NaN      - NaN      = NaN  // Expected
NaN      - Infinity = NaN
Rob W
  • 341,306
  • 83
  • 791
  • 678
  • Well, your code is larger and do 1 more operation. The only way I would use it is if you to tell me a way that my current function would fail and yours not –  Dec 15 '11 at 20:19
  • 1
    @TuxedoKnightChess Input the following value: `Infinity`. It passes the first two tests, while it's not a useful real number: `isNumber(Infinity)` returns true for your current function. – Rob W Dec 15 '11 at 20:21
  • what would be the result for `var n=2E30;`? –  Dec 15 '11 at 20:28
  • 1
    @TuxedoKnightChess: There's a real easy way to find out. – RightSaidFred Dec 15 '11 at 20:32
  • @TuxedoKnightChess I've updated the answer with another method. Two tests instead of one. – Rob W Dec 15 '11 at 20:40
  • Just to double check, both of your functions do exactly the same thing? –  Dec 15 '11 at 21:11
  • 1
    @TuxedoKnightChess The methods slightly differ, but the results are exactely equal. – Rob W Dec 15 '11 at 21:40
  • Real numbers are finite per definition. – Dmitri Zaitsev May 17 '16 at 08:09
  • how come this function is not embedded in Javascript, is for me a big huge surprise. Dealing with true numbers (integers or float) is a basic task of any programming language – João Pimentel Ferreira Jan 22 '19 at 21:19
  • btw, can I give 10 of my points to you. I feel like +1 is just not enough – João Pimentel Ferreira Jan 22 '19 at 21:27
  • your `isNumber(n)` function is *perfect* . No variable coercion and all that typical mess of javascript, no `string`, no `"1"`, no `true`, no `"true"`, no `NaN`, no `null`, no `1/0`. `n` must simply be a finite valid number (integer or float). And `0` returns true as it should be. – João Pimentel Ferreira Jan 22 '19 at 21:45
  • @DmitriZaitsev what the OP meant is not real in the mathematical sense, but merely a true number (natural, integer, rational or real numbers, in the mathematical sense). Javascript is a mess dealing with types and type coercion and believe me that this function is very, very important. – João Pimentel Ferreira Jan 22 '19 at 21:52
2

JS numbers can be among the following values:

  • Finite numbers
  • +Infinity and -Infinity
  • NaN

Then there also non-number values which are coercible to numbers, e.g. number objects. You might want to consider them numerical.

If you only want to test finite numbers, simply use Number.isFinite:

Number.isFinite(value)

var isNumber = Number.isFinite;
assert('isNumber(1)', true);
assert('isNumber(1.1)', true);
assert('isNumber(+0)', true);
assert('isNumber(-0)', true);
assert('isNumber(-1.1)', true);
assert('isNumber(Math.PI)', true);
assert('isNumber(1e300)', true);
assert('isNumber(+Infinity)', false);
assert('isNumber(-Infinity)', false);
assert('isNumber(NaN)', false);
assert('isNumber(null)', false);
assert('isNumber(undefined)', false);
assert('isNumber(true)', false);
assert('isNumber(false)', false);
assert('isNumber("123")', false);
assert('isNumber("foo")', false);
assert('isNumber(new Number(1))', false);
assert('isNumber([])', false);
assert('isNumber({})', false);
assert('isNumber(function(){})', false);
function assert(code, expected) {
  var result = eval(code);
  console.log('Test ' + (result===expected ? 'pass' : 'FAIL') + ': ', code, ' -> ', result);
}

If you want to include infinities, check the type and exclude NaN:

typeof value === "number" && !Number.isNaN(value)

function isNumber(value) {
  return typeof value === "number" && !Number.isNaN(value);
}
assert('isNumber(1)', true);
assert('isNumber(1.1)', true);
assert('isNumber(+0)', true);
assert('isNumber(-0)', true);
assert('isNumber(-1.1)', true);
assert('isNumber(Math.PI)', true);
assert('isNumber(1e300)', true);
assert('isNumber(+Infinity)', true);
assert('isNumber(-Infinity)', true);
assert('isNumber(NaN)', false);
assert('isNumber(null)', false);
assert('isNumber(undefined)', false);
assert('isNumber(true)', false);
assert('isNumber(false)', false);
assert('isNumber("123")', false);
assert('isNumber("foo")', false);
assert('isNumber(new Number(1))', false);
assert('isNumber([])', false);
assert('isNumber({})', false);
assert('isNumber(function(){})', false);
function assert(code, expected) {
  var result = eval(code);
  console.log('Test ' + (result===expected ? 'pass' : 'FAIL') + ': ', code, ' -> ', result);
}

If you want to consider number objects as numbers, you can unwrap them using

value = Number.valueOf.call(value); // throws if value was not a number object

function isNumber(value) {
  try { value = Number.prototype.valueOf.call(value); } catch(err) { }
  return Number.isFinite(value);
}
assert('isNumber(1)', true);
assert('isNumber(1.1)', true);
assert('isNumber(+0)', true);
assert('isNumber(-0)', true);
assert('isNumber(-1.1)', true);
assert('isNumber(Math.PI)', true);
assert('isNumber(1e300)', true);
assert('isNumber(+Infinity)', false);
assert('isNumber(-Infinity)', false);
assert('isNumber(NaN)', false);
assert('isNumber(null)', false);
assert('isNumber(undefined)', false);
assert('isNumber(true)', false);
assert('isNumber(false)', false);
assert('isNumber("123")', false);
assert('isNumber("foo")', false);
assert('isNumber(new Number(1))', true);
assert('isNumber([])', false);
assert('isNumber({})', false);
assert('isNumber(function(){})', false);
function assert(code, expected) {
  var result = eval(code);
  console.log('Test ' + (result===expected ? 'pass' : 'FAIL') + ': ', code, ' -> ', result);
}

If you want to include arbitrary values coercible to numbers, you can use the unary + to coerce.

value = +value; // throws if value was not number-coercible

There is also the isNaN function (not to be confused with Number.isNaN), which will first coerce and then compare with NaN. But be aware whitespace strings and null are coerced to +0, not NaN. So you might be interested in Validate decimal numbers in JavaScript - IsNumeric()

Community
  • 1
  • 1
Oriol
  • 274,082
  • 63
  • 437
  • 513
0

I use combination of parse and check for numbers.. as outlined below

function isNumber(inputValue){ return ((parseFloat(inputValue) ==0 || parseFloat(inputValue)) && !isNaN(inputValue)); };

hope this helps

0

For react or other framework users, possible solution could be:

const { onChange, value } = this.props;
return (
  <input
    type="text" // Note: I have kept this as text
    value={typeof value !== 'number' || isNaN(value) ? '' : value}
    className={classnames('input')}
    onChange={(event) =>
      onChange &&
      onChange(parseFloat(event.target.value))
    }
  />)

This works on safari as well.

Thanks.

0

It depends on what you wish to regard as a number. Your code classifies Infinity and -Infinity as numbers. If you don’t want that, replace !isNaN(n) by isFinite(n).

And your code classifies '42' (a string literal) as not being a number, due to the type check; but I supposed that’s intentional.

Jukka K. Korpela
  • 195,524
  • 37
  • 270
  • 390
-1

If you consider a number in its object wrapper to be a number, then it will fail with:

isNumber( new Number(123) )

Since a downvoter is having some comprehension troubles that couldn't be alleviated by a simple test, new Number(123) will return 'object' from the typeof test, and as such will not pass.

RightSaidFred
  • 11,209
  • 35
  • 35
  • @down-voter: Give a reason. Please tell me how `new Number(123)` will pass the `isNumber` test in the question. – RightSaidFred Dec 18 '11 at 17:06
  • I did not downvote, but your code only shows an example of something that breaks the code, without proposing a solution. The OP did not ask how to break the function, but how to *improve* the function. – Rob W Dec 28 '11 at 10:18