一个改进的isNumeric()函数?

39
在一些项目中,我需要验证一些数据并尽可能确定它是可用于数学运算的Javascript数字值。
jQuery和其他一些Javascript库已经包含了这样的函数,通常称为isNumeric。还有一个在stackoverflow上的帖子已经被广泛接受为答案,使用了与前面提到的库相同的一般例程。
function isNumber(n) {
  return !isNaN(parseFloat(n)) && isFinite(n);
}

作为我的第一篇文章,我无法在那个帖子中回复。我对被接受的帖子有问题的是,似乎存在一些角落情况影响了我正在做的一些工作,所以我进行了一些更改来尝试解决我遇到的问题。
首先,上面的代码如果参数是长度为1的数组,并且该单个元素被视为数字类型,则会返回true。在我看来,如果它是一个数组,那么它就不是数字。
为了解决这个问题,我添加了一个检查来排除逻辑中的数组。
function isNumber(n) {
  return Object.prototype.toString.call(n) !== '[object Array]' &&!isNaN(parseFloat(n)) && isFinite(n);
}

当然,你也可以使用 Array.isArray 替代 Object.prototype.toString.call(n) !== '[object Array]' 编辑:我已经更改了代码,以反映对数组的通用测试,或者您可以使用jquery $.isArray 或原型Object.isArray 我的第二个问题是负十六进制整数文字字符串(“-0xA”-> -10)没有被视为数字。 然而,正十六进制整数文字字符串(“0xA”-> 10)被视为数字。 我需要两者都是有效的数字。
然后我修改了逻辑来考虑这一点。
function isNumber(n) {
  return Object.prototype.toString.call(n) !== '[object Array]' &&!isNaN(parseFloat(n)) && isFinite(n.toString().replace(/^-/, ''));
}

如果你担心每次调用函数时都会创建正则表达式,那么你可以在闭包中重新编写它,就像这样。
isNumber = (function () {
  var rx = /^-/;

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

我随后拿了CMS的+30个测试用例并克隆了在jsfiddle上进行测试,添加了我的额外测试用例和上述解决方案。
一切似乎都按预期工作,我没有遇到任何问题。您能看到任何问题、代码或理论吗?
它可能无法取代被广泛接受/使用的答案,但如果这是您从isNumeric函数中期望的结果,那么希望这会有所帮助。 编辑:正如Bergi指出的那样,还有其他可能被认为是数字的对象,最好是白名单而不是黑名单。考虑到这一点,我会添加以下标准。
我希望我的isNumeric函数只考虑数字或字符串。
考虑到这一点,最好使用
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(/^-/, ''));
}

这已作为测试22添加


5
不能使用 typeof 来测试数组,因为 typeof array 会返回 "object" - Felix Kling
11
应该将此迁移到http://codereview.stackexchange.com,或者在该问题上发布答案。 - the system
1
@thesystem 很遗憾,由于这个问题是“受保护的”(需要10个声望才能回答),所以OP无法回答。我猜这可能适用于codereview(我在那里不活跃,所以我不确定),但这不是这里的主题吗? - Wesley Murch
4
@thesystem 我认为你可能是对的,除了“这通过了我的所有测试,你们觉得怎么样?”之外,这里实际上没有任何问题。也许这个帖子应该被关闭,并作为回答发布在https://dev59.com/3nVD5IYBdhLWcg3wU56H中。 - Wesley Murch
1
@Wesley Munch:现在我有这个能力,我会用修改后的措辞将其发布在那里。 - Xotic750
显示剩余9条评论
7个回答

4
在我看来,如果它是一个数组,那么它就不是数值型的。为了解决这个问题,我添加了一个检查,排除了数组逻辑。
你可能会在任何其他对象中遇到这个问题,例如{toString:function(){return "1.2";}}。哪些对象你认为是数值型的?Number对象?没有?
与其尝试去黑名单一些未通过测试的事物,不如明确将你想成数值型的事物列入白名单。你的函数应该得到什么,原始字符串和数字?然后对它们进行精确定义的测试:
(typeof n == "string" || typeof n == "number")

这是一个合理的观点,如果是这样的话,那么我会更改我的条件为:如果对象是数字或字符串。 - Xotic750

1
如果您可以使用正则表达式,这可能是一个解决方法:
function (n) 
    { 
    return (Object.prototype.toString.call(n) === '[object Number]' ||
            Object.prototype.toString.call(n) === '[object String]') && 
           (typeof(n) != 'undefined')  &&  (n!=null) && 
           (/^-?\d+((.\d)?\d*(e[-]?\d)?(\d)*)$/.test(n.toString()) ||
           /^-?0x[0-9A-F]+$/.test(n.toString()));
    }

编辑:修复了十六进制数字的问题


我认为确保 JavaScript 不会转换值的唯一方法是直接查看该值。使用与人类评估数字相同的规则。 - Rembunator

0
function isNumber(value){
    return !isNaN(parseFloat(value)) && 
        isFinite(value.toString().replace(/^-/, '')) && 
        typeof value !== 'object';

}

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

抱歉,我看不出这些有任何改进的地方。 - Xotic750

0

以上的库和函数我还没有测试过,所以不知道它在提供的测试中表现如何,但我认为为这样一个函数包含整个库可能有点多余。 - Xotic750
1
内部实际上只是使用 Object.prototype.toString.call(val) 并检查它是否等于 "[object Number]"...所以如果你有一个字符串(而不是数字)并且不确定它是否为数字,那么这种方法就无法帮助你,我相信这就是 OP 想要的。 - Matt Browne
@Xotic750,你根本不需要添加整个库。这就是AMD的全部意义,将功能分解为模块,以便您只加载实际使用的内容。 - user339827

0
function isNumber(value){return typeof value == 'number';}

1
请看jsfiddle上的测试结果,您提供的代码是第19个并且失败了。 - Xotic750

0

这样怎么样:

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

抱歉,但它失败了(请参见测试函数20)。 - Xotic750

0

isNaN函数用于检查值是否为数字。如果值是数字,则返回true,否则返回false。

代码:

 <script>

         function IsNumeric(val) {

              if (isNaN(parseFloat(val))) {

                 return false;

          }

          return true

  }


  bool IsNumeric(string);


</script>

1
请查看测试函数4(与您发布的代码相同),它失败了。 - Xotic750

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接