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.
function isNumber[n] {
return !isNaN[parseFloat[n]] && isFinite[n];
}
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
, jquery $.isArray
or prototype Object.isArray
instead of Object.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.
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
var 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.
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
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[/^-/, '']];
}
Test the solutions
var testHelper = function[] {
var testSuite = function[] {
test["Integer Literals", function[] {
ok[isNumber["-10"], "Negative integer string"];
ok[isNumber["0"], "Zero string"];
ok[isNumber["5"], "Positive integer string"];
ok[isNumber[-16], "Negative integer number"];
ok[isNumber[0], "Zero integer number"];
ok[isNumber[32], "Positive integer number"];
ok[isNumber["040"], "Octal integer literal string"];
ok[isNumber[0144], "Octal integer literal"];
ok[isNumber["-040"], "Negative Octal integer literal string"];
ok[isNumber[-0144], "Negative Octal integer literal"];
ok[isNumber["0xFF"], "Hexadecimal integer literal string"];
ok[isNumber[0xFFF], "Hexadecimal integer literal"];
ok[isNumber["-0xFF"], "Negative Hexadecimal integer literal string"];
ok[isNumber[-0xFFF], "Negative Hexadecimal integer literal"];
}];
test["Foating-Point Literals", function[] {
ok[isNumber["-1.6"], "Negative floating point string"];
ok[isNumber["4.536"], "Positive floating point string"];
ok[isNumber[-2.6], "Negative floating point number"];
ok[isNumber[3.1415], "Positive floating point number"];
ok[isNumber[8e5], "Exponential notation"];
ok[isNumber["123e-2"], "Exponential notation string"];
}];
test["Non-Numeric values", function[] {
equals[isNumber[""], false, "Empty string"];
equals[isNumber[" "], false, "Whitespace characters string"];
equals[isNumber["\t\t"], false, "Tab characters string"];
equals[isNumber["abcdefghijklm1234567890"], false, "Alphanumeric character string"];
equals[isNumber["xabcdefx"], false, "Non-numeric character string"];
equals[isNumber[true], false, "Boolean true literal"];
equals[isNumber[false], false, "Boolean false literal"];
equals[isNumber["bcfed5.2"], false, "Number with preceding non-numeric characters"];
equals[isNumber["7.2acdgs"], false, "Number with trailling non-numeric characters"];
equals[isNumber[undefined], false, "Undefined value"];
equals[isNumber[null], false, "Null value"];
equals[isNumber[NaN], false, "NaN value"];
equals[isNumber[Infinity], false, "Infinity primitive"];
equals[isNumber[Number.POSITIVE_INFINITY], false, "Positive Infinity"];
equals[isNumber[Number.NEGATIVE_INFINITY], false, "Negative Infinity"];
equals[isNumber[new Date[2009, 1, 1]], false, "Date object"];
equals[isNumber[new Object[]], false, "Empty object"];
equals[isNumber[function[] {}], false, "Instance of a function"];
equals[isNumber[[]], false, "Empty Array"];
equals[isNumber[["-10"]], false, "Array Negative integer string"];
equals[isNumber[["0"]], false, "Array Zero string"];
equals[isNumber[["5"]], false, "Array Positive integer string"];
equals[isNumber[[-16]], false, "Array Negative integer number"];
equals[isNumber[[0]], false, "Array Zero integer number"];
equals[isNumber[[32]], false, "Array Positive integer number"];
equals[isNumber[["040"]], false, "Array Octal integer literal string"];
equals[isNumber[[0144]], false, "Array Octal integer literal"];
equals[isNumber[["-040"]], false, "Array Negative Octal integer literal string"];
equals[isNumber[[-0144]], false, "Array Negative Octal integer literal"];
equals[isNumber[["0xFF"]], false, "Array Hexadecimal integer literal string"];
equals[isNumber[[0xFFF]], false, "Array Hexadecimal integer literal"];
equals[isNumber[["-0xFF"]], false, "Array Negative Hexadecimal integer literal string"];
equals[isNumber[[-0xFFF]], false, "Array Negative Hexadecimal integer literal"];
equals[isNumber[[1, 2]], false, "Array with more than 1 Positive interger number"];
equals[isNumber[[-1, -2]], false, "Array with more than 1 Negative interger number"];
}];
}
var functionsToTest = [
function[n] {
return !isNaN[parseFloat[n]] && isFinite[n];
},
function[n] {
return !isNaN[n] && !isNaN[parseFloat[n]];
},
function[n] {
return !isNaN[[n]];
},
function[n] {
return !isNaN[parseFloat[n]];
},
function[n] {
return typeof[n] != "boolean" && !isNaN[n];
},
function[n] {
return parseFloat[n] === Number[n];
},
function[n] {
return parseInt[n] === Number[n];
},
function[n] {
return !isNaN[Number[String[n]]];
},
function[n] {
return !isNaN[+['' + n]];
},
function[n] {
return [+n] == n;
},
function[n] {
return n && /^-?\d+[\.\d+]?$/.test[n + ''];
},
function[n] {
return isFinite[Number[String[n]]];
},
function[n] {
return isFinite[String[n]];
},
function[n] {
return !isNaN[n] && !isNaN[parseFloat[n]] && isFinite[n];
},
function[n] {
return parseFloat[n] == n;
},
function[n] {
return [n - 0] == n && n.length > 0;
},
function[n] {
return typeof n === 'number' && isFinite[n];
},
function[n] {
return !Array.isArray[n] && !isNaN[parseFloat[n]] && isFinite[n.toString[].replace[/^-/, '']];
}
];
// Examines the functionsToTest array, extracts the return statement of each function
// and fills the toTest select element.
var fillToTestSelect = function[] {
for [var i = 0; i < functionsToTest.length; i++] {
var f = functionsToTest[i].toString[];
var option = /[\s\S]*return [[\s\S]*];/.exec[f][1];
$["#toTest"].append['' + [i + 1] + '. ' + option + ''];
}
}
var performTest = function[functionNumber] {
reset[]; // Reset previous test
$["#tests"].html[""]; //Clean test results
isNumber = functionsToTest[functionNumber]; // Override the isNumber global function with the one to test
testSuite[]; // Run the test
// Get test results
var totalFail = 0;
var totalPass = 0;
$["b.fail"].each[function[] {
totalFail += Number[$[this].html[]];
}];
$["b.pass"].each[function[] {
totalPass += Number[$[this].html[]];
}];
$["#testresult"].html[totalFail + " of " + [totalFail + totalPass] + " test failed."];
$["#banner"].attr["class", ""].addClass[totalFail > 0 ? "fail" : "pass"];
}
return {
performTest: performTest,
fillToTestSelect: fillToTestSelect,
testSuite: testSuite
};
}[];
$[document].ready[function[] {
testHelper.fillToTestSelect[];
testHelper.performTest[0];
$["#toTest"].change[function[] {
testHelper.performTest[$[this].children[":selected"].val[]];
}];
}];
isNumber Test Cases
Mozilla/5.0 [X11; Linux x86_64] AppleWebKit/537.11 [KHTML, like Gecko] Chrome/23.0.1271.95 Safari/537.11
Select function to test:
-
Integer Literals [0, 10, 10]
- Negative integer string
- Zero string
- Positive integer string
- Negative integer number
- Zero integer number
- Positive integer number
- Octal integer literal string
- Octal integer literal
- Hexadecimal integer literal string
- Hexadecimal integer literal
-
Foating-Point Literals [0, 6, 6]
- Negative floating point string
- Positive floating point string
- Negative floating point number
- Positive floating point number
- Exponential notation
- Exponential notation string
-
Non-Numeric values [0, 18, 18]
- Empty string: false
- Whitespace characters string: false
- Tab characters string: false
- Alphanumeric character string: false
- Non-numeric character string: false
- Boolean true literal: false
- Boolean false literal: false
- Number with preceding non-numeric characters: false
- Number with trailling non-numeric characters: false
- Undefined value: false
- Null value: false
- NaN value: false
- Infinity primitive: false
- Positive Infinity: false
- Negative Infinity: false
- Date object: false
- Empty object: false
- Instance of a function: false
This page contains tests for a set of isNumber functions. To see them, take a look at the source.
Tests completed in 0 milliseconds.
0 tests of 0 failed.