An improved isNumeric() function?

2019-03-09 15:43发布

During some projects I have needed to validate some data and be as certain as possible that it is javascript numerical value that can be used in mathematical operations.

jQuery, and some other javascript libraries already include such a function, usually called isNumeric. There is also a post on stackoverflow that has been widely accepted as the answer, the same general routine that the fore mentioned libraries are using.

function isNumber(n) {
  return !isNaN(parseFloat(n)) && isFinite(n);
}

Being my first post, I was unable to reply in that thread. The issue that I had with the accepted post was that there appear to be some corner cases that affected some work that I was doing, and so I made some changes to try and cover the issue I was having.

First, the code above would return true if the argument was an array of length 1, and that single element was of a type deemed as numeric by the above logic. In my opinion, if it's an array then its not numeric.

To alleviate this problem, I added a check to discount arrays from the logic

function isNumber(n) {
  return Object.prototype.toString.call(n) !== '[object Array]' &&!isNaN(parseFloat(n)) && isFinite(n);
}

Of course, you could also use Array.isArray instead of Object.prototype.toString.call(n) !== '[object Array]'

EDIT: I've changed the code to reflect a generic test for array, or you could use jquery $.isArray or prototypes Object.isArray

My second issue was that Negative Hexadecimal integer literal strings ("-0xA" -> -10) were not being counted as numeric. However, Positive Hexadecimal integer literal strings ("0xA" -> 10) wrere treated as numeric. I needed both to be valid numeric.

I then modified the logic to take this into account.

function isNumber(n) {
  return Object.prototype.toString.call(n) !== '[object Array]' &&!isNaN(parseFloat(n)) && isFinite(n.toString().replace(/^-/, ''));
}

If you are worried about the creation of the regex each time the function is called then you could rewrite it within a closure, something like this

isNumber = (function () {
  var rx = /^-/;

  return function (n) {
      return Object.prototype.toString.call(n) !== '[object Array]' && !isNaN(parseFloat(n)) && isFinite(n.toString().replace(rx, ''));
  };
}());

I then took CMSs +30 test cases and cloned the testing on jsfiddle added my extra test cases and my above described solution.

Everything appears to be working as expected and I haven't experienced any issues. Are there any issues, code or theoretical, that you can see?

It may not replace the widely accepted/used answer but if this is what you are expecting as results from your isNumeric function then hopefully this will be of some help.

EDIT: As pointed out by Bergi, there are other possible objects that could be considered numeric and it would be better to whitelist than blacklist. With this in mind I would add to the criteria.

I want my isNumeric function to consider only Numbers or Strings

With this in mind, it would be better to use

function isNumber(n) {
  return (Object.prototype.toString.call(n) === '[object Number]' || Object.prototype.toString.call(n) === '[object String]') &&!isNaN(parseFloat(n)) && isFinite(n.toString().replace(/^-/, ''));
}

This has been added as test 22

7条回答
叛逆
2楼-- · 2019-03-09 16:46
function isNumber(value){return typeof value == 'number';}
查看更多
登录 后发表回答