Улучшенная функция isNumeric()?

Во время некоторых проектов мне нужно было проверить некоторые данные и быть как можно более уверенными, что это числовое значение javascript, которое можно использовать в математических операциях.

jQuery и некоторые другие библиотеки javascript уже включают такую ​​функцию, обычно называемую isNumeric. Существует также сообщение о стековерсии, которое широко принимается в качестве ответа, та же самая общая процедура, которую используют вышеупомянутые библиотеки.

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

Будучи моим первым сообщением, я не смог ответить в этой теме. Проблема, которая возникла у меня с принятым постом, заключалась в том, что, как мне кажется, были некоторые угловые случаи, которые повлияли на некоторую работу, которую я выполнял, и поэтому я внес некоторые изменения, чтобы попытаться осветить проблему, которая у меня была.

Во-первых, приведенный выше код вернул бы значение true, если аргумент представлял собой массив длиной 1, и этот единственный элемент имел тип, считающийся числовым по приведенной выше логике. На мой взгляд, если это массив, то он не числовой.

Чтобы облегчить эту проблему, я добавил чек для дисконтирования массивов из логики

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, то, надеюсь, это поможет вам.

РЕДАКТИРОВАТЬ: Как указал Берги, есть другие возможные объекты, которые можно считать числовыми, и было бы лучше, чтобы белый список, чем черный список. Имея это в виду, я бы добавил к критериям.

Я хочу, чтобы моя функция 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

7 ответов

На мой взгляд, если это массив, то он не числовой. Чтобы облегчить эту проблему, я добавил чек для дисконтирования массивов из логики

Вы можете иметь эту проблему с любым другим объектом, например, {toString:function(){return "1.2";}}, Какие объекты вы считаете числовыми? Number объекты? Никто?

Вместо того, чтобы пытаться занести в черный список некоторые вещи, которые не прошли ваш тест, вы должны явно занести в белый список то, что вы хотите сделать числовым. Что ваша функция должна получить, примитивные строки и числа? Затем протестируйте именно для них:

(typeof n == "string" || typeof n == "number")

Если вы можете использовать регулярные выражения, это может помочь:

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()));
    }

редактировать: исправлена ​​проблема с шестнадцатеричными числами

Функция isNaN используется для проверки, является ли значение числовым или нет. Если значения являются числовыми, возвращается true, иначе возвращается false.

код:

 <script>

         function IsNumeric(val) {

              if (isNaN(parseFloat(val))) {

                 return false;

          }

          return true

  }


  bool IsNumeric(string);


</script>

Если AMD звучит хорошо для вас, посмотрите на isNumber() mout's.

Как насчет:

function isNumber(value) {
  value = Number(value);
  return typeof value === 'number' && !isNaN(value) && isFinite(value);
}
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]';
}
function isNumber(value){return typeof value == 'number';}
Другие вопросы по тегам