我希望在与旧的VB6 IsNumeric()函数相同的概念空间中有什么东西?
当前回答
如果有人对此感到失望的话,我花了一些时间来修补moment.js(https://github.com/moment/moment). 我从中得到了一些东西:
function isNumeric(val) {
var _val = +val;
return (val !== val + 1) //infinity check
&& (_val === +val) //Cute coercion check
&& (typeof val !== 'object') //Array/object check
}
处理以下情况:
真!:
isNumeric("1"))
isNumeric(1e10))
isNumeric(1E10))
isNumeric(+"6e4"))
isNumeric("1.2222"))
isNumeric("-1.2222"))
isNumeric("-1.222200000000000000"))
isNumeric("1.222200000000000000"))
isNumeric(1))
isNumeric(0))
isNumeric(-0))
isNumeric(1010010293029))
isNumeric(1.100393830000))
isNumeric(Math.LN2))
isNumeric(Math.PI))
isNumeric(5e10))
错误!:
isNumeric(NaN))
isNumeric(Infinity))
isNumeric(-Infinity))
isNumeric())
isNumeric(undefined))
isNumeric('[1,2,3]'))
isNumeric({a:1,b:2}))
isNumeric(null))
isNumeric([1]))
isNumeric(new Date()))
具有讽刺意味的是,我最纠结的是:
isNumeric(new Number(1)) => false
欢迎提出任何建议。:]
其他回答
老问题,但给出的答案中缺少几点。
科学记数法。
!isNaN('e+30')是正确的,但在大多数情况下,当人们要求数字时,他们不想匹配像1e+30这样的数字。
大浮点数的行为可能很奇怪
观察(使用Node.js):
> var s = Array(16 + 1).join('9')
undefined
> s.length
16
> s
'9999999999999999'
> !isNaN(s)
true
> Number(s)
10000000000000000
> String(Number(s)) === s
false
>
另一方面:
> var s = Array(16 + 1).join('1')
undefined
> String(Number(s)) === s
true
> var s = Array(15 + 1).join('9')
undefined
> String(Number(s)) === s
true
>
因此,如果期望String(Number(s))==s,那么最好将字符串限制在最多15位(省略前导零后)。
无穷
> typeof Infinity
'number'
> !isNaN('Infinity')
true
> isFinite('Infinity')
false
>
考虑到所有这些,检查给定字符串是否为满足以下所有条件的数字:
非科学记数法可预测地转换为数字并返回到字符串有限的
这不是一项容易的任务。下面是一个简单的版本:
function isNonScientificNumberString(o) {
if (!o || typeof o !== 'string') {
// Should not be given anything but strings.
return false;
}
return o.length <= 15 && o.indexOf('e+') < 0 && o.indexOf('E+') < 0 && !isNaN(o) && isFinite(o);
}
然而,即使是这一点也远未完成。这里不处理前导零,但它们确实会破坏长度测试。
我喜欢这种简单。
Number.isNaN(Number(value))
以上是常规的Javascript,但我将其与typescript类型保护器一起用于智能类型检查。这对于类型脚本编译器提供正确的智能感知和无类型错误非常有用。
打字保护装置
警告:请参阅Jeremy在下面的评论。这在某些值上有一些问题,我现在没有时间修复它,但使用typescript类型保护的想法很有用,因此我不会删除此部分。
isNotNumber(value: string | number): value is string {
return Number.isNaN(Number(this.smartImageWidth));
}
isNumber(value: string | number): value is number {
return Number.isNaN(Number(this.smartImageWidth)) === false;
}
假设您有一个属性宽度,即number | string。您可能希望根据它是否是字符串来执行逻辑。
var width: number|string;
width = "100vw";
if (isNotNumber(width))
{
// the compiler knows that width here must be a string
if (width.endsWith('vw'))
{
// we have a 'width' such as 100vw
}
}
else
{
// the compiler is smart and knows width here must be number
var doubleWidth = width * 2;
}
类型保护足够聪明,可以将if语句中的宽度类型限制为ONLY字符串。这允许编译器允许width.endsWith(…),如果类型为string | number,则不允许。
你可以随意调用类型保护器isNotNumber,isNumber,isString,isNotString,但我认为isString有点模棱两可,很难理解。
这里是isNumber实现的高性能(2.5*10^7迭代/s@3.8GHz Haswell)版本。它适用于我能找到的每个测试用例(包括符号):
var isNumber = (function () {
var isIntegerTest = /^\d+$/;
var isDigitArray = [!0, !0, !0, !0, !0, !0, !0, !0, !0, !0];
function hasLeading0s (s) {
return !(typeof s !== 'string' ||
s.length < 2 ||
s[0] !== '0' ||
!isDigitArray[s[1]] ||
isIntegerTest.test(s));
}
var isWhiteSpaceTest = /\s/;
return function isNumber (s) {
var t = typeof s;
var n;
if (t === 'number') {
return (s <= 0) || (s > 0);
} else if (t === 'string') {
n = +s;
return !((!(n <= 0) && !(n > 0)) || n === '0' || hasLeading0s(s) || !(n !== 0 || !(s === '' || isWhiteSpaceTest.test(s))));
} else if (t === 'object') {
return !(!(s instanceof Number) || ((n = +s), !(n <= 0) && !(n > 0)));
}
return false;
};
})();
这是基于之前的一些回答和评论。以下内容涵盖了所有边缘情况,也相当简洁:
const isNumRegEx = /^-?(\d*\.)?\d+$/;
function isNumeric(n, allowScientificNotation = false) {
return allowScientificNotation ?
!Number.isNaN(parseFloat(n)) && Number.isFinite(n) :
isNumRegEx.test(n);
}
function isNumberCandidate(s) {
const str = (''+ s).trim();
if (str.length === 0) return false;
return !isNaN(+str);
}
console.log(isNumberCandidate('1')); // true
console.log(isNumberCandidate('a')); // false
console.log(isNumberCandidate('000')); // true
console.log(isNumberCandidate('1a')); // false
console.log(isNumberCandidate('1e')); // false
console.log(isNumberCandidate('1e-1')); // true
console.log(isNumberCandidate('123.3')); // true
console.log(isNumberCandidate('')); // false
console.log(isNumberCandidate(' ')); // false
console.log(isNumberCandidate(1)); // true
console.log(isNumberCandidate(0)); // true
console.log(isNumberCandidate(NaN)); // false
console.log(isNumberCandidate(undefined)); // false
console.log(isNumberCandidate(null)); // false
console.log(isNumberCandidate(-1)); // true
console.log(isNumberCandidate('-1')); // true
console.log(isNumberCandidate('-1.2')); // true
console.log(isNumberCandidate(0.0000001)); // true
console.log(isNumberCandidate('0.0000001')); // true
console.log(isNumberCandidate(Infinity)); // true
console.log(isNumberCandidate(-Infinity)); // true
console.log(isNumberCandidate('Infinity')); // true
if (isNumberCandidate(s)) {
// use +s as a number
+s ...
}