What's the cleanest, most effective way to validate decimal numbers in JavaScript?
Bonus points for:
- Clarity. Solution should be clean and simple.
- Cross-platform.
Test cases:
01. IsNumeric('-1') => true
02. IsNumeric('-1.5') => true
03. IsNumeric('0') => true
04. IsNumeric('0.42') => true
05. IsNumeric('.42') => true
06. IsNumeric('99,999') => false
07. IsNumeric('0x89f') => false
08. IsNumeric('#abcdef') => false
09. IsNumeric('1.2.3') => false
10. IsNumeric('') => false
11. IsNumeric('blah') => false
The accepted answer failed your test #7 and I guess it's because you changed your mind. So this is a response to the accepted answer, with which I had issues.
During some projects I have needed to validate some data and be as certain as possible that it is a 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 afore mentioned libraries are using.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
Of course, you could also use
Array.isArray
, jquery$.isArray
or prototypeObject.isArray
instead ofObject.prototype.toString.call(n) !== '[object Array]'
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) were treated as numeric. I needed both to be valid numeric.
I then modified the logic to take this into account.
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
I then took CMSs +30 test cases and cloned the testing on jsfiddle added my extra test cases and my above described solution.
It may not replace the widely accepted/used answer but if this is more of 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
Test the solutions
The following seems to works fine for many cases:
This is built on top of this answer (which is for this answer too): https://stackoverflow.com/a/1561597/1985601
@Joel's answer is pretty close, but it will fail in the following cases:
Some time ago I had to implement an
IsNumeric
function, to find out if a variable contained a numeric value, regardless of its type, it could be aString
containing a numeric value (I had to consider also exponential notation, etc.), aNumber
object, virtually anything could be passed to that function, I couldn't make any type assumptions, taking care of type coercion (eg.+true == 1;
buttrue
shouldn't be considered as"numeric"
).I think is worth sharing this set of +30 unit tests made to numerous function implementations, and also share the one that passes all my tests:
P.S. isNaN & isFinite have a confusing behavior due to forced conversion to number. In ES6, Number.isNaN & Number.isFinite would fix these issues. Keep that in mind when using them.
Update : Here's how jQuery does it now (2.2-stable):
Update : Angular 4.3:
This way seems to work well:
And to test it:
I borrowed that regex from http://www.codetoad.com/javascript/isnumeric.asp. Explanation:
Here's a lil bit improved version (probably the fastest way out there) that I use instead of exact jQuery's variant, I really don't know why don't they use this one:
The downside of jQuery's version is that if you pass a string with leading numerics and trailing letters like
"123abc"
theparseFloat | parseInt
will extract the numeric fraction out and return 123, BUT, the second guardisFinite
will fail it anyway. With the unary+
operator it will die on the very first guard since + throws NaN for such hybrids :) A little performance yet I think a solid semantic gain.Since jQuery 1.7, you can use
jQuery.isNumeric()
:Just note that unlike what you said,
0x89f
is a valid number (hexa)