Питання Підтвердження десяткових чисел у JavaScript - IsNumeric ()


Який найчистіший, найефективніший спосіб перевірки десяткових чисел у JavaScript?

Бонусні очки за:

  1. Ясність Рішення має бути чистим і простим.
  2. Крос-платформенний

Тестові випадки:

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

2156


походження


Тільки примітка 99 999 є дійсною цифрою у Франції, вона така ж, як у форматі uk / us, 99.999, тому, якщо ви читаєте в рядку із слова "введення", тоді 99,999 може бути вірним. - Re0sless
Також перевірте цей пост і чудові коментарі. - powtac
Десяткова кома є стандартом у всій Європі та Росії (крім Великобританії) - Calmarius
jQuery 1.7 представила jQuery.isNumeric функція корисності: api.jquery.com/jQuery.isNumeric - Ates Goral
jQuery.isNumeric спричинить сьомий тестовий випадок OP (IsNumeric('0x89f') => *false*) Я не впевнений, що я згоден з цим тестовим прикладом. - Tim Lehner


Відповіді:


@ Відповідь Джозеля це досить близько, але воно вийде з ладу в наступних випадках:

// Whitespace strings:
IsNumeric(' ')    == true;
IsNumeric('\t\t') == true;
IsNumeric('\n\r') == true;

// Number literals:
IsNumeric(-1)  == false;
IsNumeric(0)   == false;
IsNumeric(1.1) == false;
IsNumeric(8e5) == false;

Якийсь час назад мені довелося втілити в життя IsNumeric функція, щоб з'ясувати, чи містить змінна числове значення незалежно від його типу, це може бути а String що містить числові значення (я мав також розглянути експоненціальні позначення і т. д.), a Number об'єкт, практично щось може бути передане на цю функцію, я не міг зробити будь-які припущення типу, піклуючись про примус типу (наприклад,. +true == 1; але true не слід розглядати як "numeric")

Я думаю, варто поділитися цим набором +30 одиниць випробувань виконані в численних реалізаціях функцій, а також поділяють той, який проходить всі мої тести:

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

П.С.  isNaN & isFinite мати заплутану поведінку через примусове перетворення на номер. У ES6 Номер & Номер.інець виправити ці проблеми. Майте це на увазі під час їх використання.


Оновити : Ось як працює jQuery зараз (2.2-stable):

isNumeric: function(obj) {
    var realStringObj = obj && obj.toString();
    return !jQuery.isArray(obj) && (realStringObj - parseFloat(realStringObj) + 1) >= 0;
}

Оновити : Кутовий 4.3:

export function isNumeric(value: any): boolean {
    return !isNaN(value - parseFloat(value));
}

2760



Ця відповідь є правильною. stackoverflow.com/questions/18082/... Відповідь Джоеля не так. Як неправильна відповідь зібрала більше голосів, ніж правильна? - Arvin
це не вдається з іншими локалями, де ми використовуємо десяткові коми, але додаємо `n = n.replace (/, /, '.");'; перед тим як повернутися, щоб це виправити. - Zoltan Lengyel
@RobG, така поведінка є навмисною 2e308 > Number.MAX_VALUE з 2e308 == Infinity. Якщо вам потрібна функція, яка повертається true також для позитивних та негативних значень нескінченності, перевірте функцію № 2 в тестовий набір. Підбадьорює - CMS
До речі, підроздільні тести зараз використовуються jQuery проект - CMS
jQuery тепер також використовуючи ця реалізація - RichardTowers


Арррхх! Не слухайте відповіді регулярного виразу. RegEx є кимчиком для цього, і я не кажу тільки про продуктивність. Неважко помітити помилки у вашому регулярному вираженні.

Якщо ви не можете використовувати isNaN(), це повинно працювати набагато краще:

function IsNumeric(input)
{
    return (input - 0) == input && (''+input).trim().length > 0;
}

Ось як це працює:

The (input - 0) вираз примушує JavaScript робити примус типу на вашу вхідну цінність; його спочатку слід інтерпретувати як число для операції віднімання. Якщо це перетворення на число не вдасться, вираз призведе до NaN. Це числовий Результат тоді порівнюється з початковим значенням, в якому ви перейшли. Оскільки ліва частина тепер чисельна, типовий примус знову використовується. Тепер, коли введення з обох сторін було примусово до такого ж типу з того самого вихідного значення, ви думаєте, що вони завжди повинні бути однаковими (завжди вірно). Однак існує спеціальне правило, яке говорить NaN ніколи не дорівнює NaN, і тому значення, яке неможливо перетворити на число (і тільки значення, які неможливо перетворити на номери), призведе до помилки.

Перевірка довжини - це особливий випадок, що стосується пустих рядків. Також зверніть увагу на те, що він потрапляє на тест 0x89f, але це пов'язано з тим, що в багатьох середовищах це правильний спосіб визначити літературний номер. Якщо ви хочете зловити цей конкретний сценарій, ви можете додати додаткову перевірку. Навіть краще, якщо це ваша причина не використовувати isNaN() то просто замініть свою функцію навколо isNaN() що також може зробити додаткову перевірку.

Таким чином, якщо ви хочете знати, чи можна перетворити значення в число, насправді спробуйте перетворити його в число.


Я повернувся і зробив кілька досліджень для чому рядок білого простору не мав очікуваного виводу, і я думаю, що я зараз це отримую: примусово додати порожній рядок 0 а не NaN. Просто обрізка рядка перед перевіркою довжини буде обробляти цей випадок.

Виконується тестування блоку на новий код, і воно не спрацьовує тільки на нескінченність і логічні літерали, і єдиний час, коли проблема - це те, що ви створюєте код (насправді, хто буде вводити літературний текст і перевірити, чи він числовий? Ти повинен знати), і це буде якийсь дивний код для генерації.

Але знову ж таки Єдина причина коли-небудь використовувати це, якщо з якоїсь причини вам слід уникати isNaN ().


315



ще краще, якщо вам просто потрібно створити обліковий запис для спеціального випадку 0x89f, оберніть функцію IsNumeric () навколо isNaN (), яка потім робить вашу спеціальну перевірку, лише якщо isNaN () повертає false. - Joel Coehoorn
Це не вдається до рядків пробілу, наприклад IsNumeric(' '), IsNumeric('\n\t')і т. д. все повертаються true - Crescent Fresh
Це також буде невдалим Number літералами IsNumeric(5) == false; перевірте набір одиничних тестів, які я опублікував, ця функція є номером 16 на тестовий комплект. stackoverflow.com/questions/18082/... - CMS
Я не можу повірити, що ніхто не вказав на використання регулярного виразу (заміни) після попередження про невикористання регулярних виразів ... Приміром, заміщення пробілу простіше, ніж проривне число, але це все одно абсолютно "кийка". - Patrick M
@Oriol Це велика проблема ... без виправлень безпеки, випущених після цієї дати, відхід від XP має бути пріоритетом. - Joel Coehoorn


Здається, це добре працює:

function IsNumeric(input){
    var RE = /^-{0,1}\d*\.{0,1}\d+$/;
    return (RE.test(input));
}

І перевірити це:

// alert(TestIsNumeric());

function TestIsNumeric(){
    var results = ''
    results += (IsNumeric('-1')?"Pass":"Fail") + ": IsNumeric('-1') => true\n";
    results += (IsNumeric('-1.5')?"Pass":"Fail") + ": IsNumeric('-1.5') => true\n";
    results += (IsNumeric('0')?"Pass":"Fail") + ": IsNumeric('0') => true\n";
    results += (IsNumeric('0.42')?"Pass":"Fail") + ": IsNumeric('0.42') => true\n";
    results += (IsNumeric('.42')?"Pass":"Fail") + ": IsNumeric('.42') => true\n";
    results += (!IsNumeric('99,999')?"Pass":"Fail") + ": IsNumeric('99,999') => false\n";
    results += (!IsNumeric('0x89f')?"Pass":"Fail") + ": IsNumeric('0x89f') => false\n";
    results += (!IsNumeric('#abcdef')?"Pass":"Fail") + ": IsNumeric('#abcdef') => false\n";
    results += (!IsNumeric('1.2.3')?"Pass":"Fail") + ": IsNumeric('1.2.3') => false\n";
    results += (!IsNumeric('')?"Pass":"Fail") + ": IsNumeric('') => false\n";
    results += (!IsNumeric('blah')?"Pass":"Fail") + ": IsNumeric('blah') => false\n";

    return results;
}

Я запозичив цей регулярний вираз з http://www.codetoad.com/javascript/isnumeric.asp. Пояснення:

/^ match beginning of string
-{0,1} optional negative sign
\d* optional digits
\.{0,1} optional decimal point
\d+ at least one digit
$/ match end of string

58



// також слід додати до результатів тесту + = (! IsNumeric ('-')?) "Pass": "Fail") + ": IsNumeric ('-') => false \ n"; результати + = (! IsNumeric ('01 ')? "Передати": "Відмовитися") + ": IsNumeric ('01') => false \ n"; Результати + = (! IsNumeric ('- 01')? "Передати": "Відмовитися") + ": IsNumeric ('- 01') => false \ n"; результати + = (! IsNumeric ('000')? "Pass": "Fail") + ": IsNumeric ('000') => false \ n"; - Dan
що це робить? / ^ - {0,1} \ d * \. {0,1} \ d + $ / - call-me
може "{0,1}" замінити на "?", тому ваш регулярний вираз виглядатиме так: /^-?\d*\.?\d+$/? - Cloud


Yahoo! Інтерфейс користувача використовує це:

isNumber: function(o) {
    return typeof o === 'number' && isFinite(o);
}

45



Це більше перевіряє тип змінної на відміну від вмісту номера. Також буде збій на числа, створені за допомогою new Number(1). - alex
Як каже Алекс, насправді це не відповідає поставленому питанню, оскільки це не вдасться, якщо o = "1001". - Case


function IsNumeric(num) {
     return (num >=0 || num < 0);
}

Це також стосується номерів типу 0x23.


44



IsNumeric(''), IsNumeric(' '), IsNumeric(true), IsNumeric(false), IsNumeric(null) повернутися true замість false. - Oriol
Я поліпшив це: stackoverflow.com/a/20712631/1985601 - daniel1426


Прийнята відповідь не пройшла тест № 7, і я думаю, це тому, що ви змінили свій розум. Отже, це відповідь на прийняту відповідь, з якою я мав проблеми.

Під час деяких проектів мені потрібно було перевірити деякі дані та бути максимально впевненим в тому, що це числове значення для JavaScript, яке можна використовувати в математичних операціях.

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

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

По-перше, код, наведений вище, повернеться істинно, якщо аргумент масив довжини 1, і що одиничний елемент був таким, який вважається числовим з наведеної вище логіки. На мій погляд, якщо це масив, то його не числове значення.

Щоб полегшити цю проблему, я додав чек для масивів знижок з логіки

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

Звичайно, ви могли б також використовувати Array.isArray, jquery $.isArray або прототип Object.isArray замість Object.prototype.toString.call(n) !== '[object Array]'

Друга проблема полягала в тому, що мінус-слова шістнадцяткові цілі буквенні рядки ("-0xA" -> -10) не вважалися числовими. Проте, позитивні шістнадцяткові цілі буквенні рядки ("0xA" -> 10) розглядалися як числові. Мені потрібні як дійсні числові.

Тоді я змінив логіку, щоб це враховувати.

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

Якщо ви турбуєтеся про створення регулярного виразу кожного разу, коли функція викликається, ви можете переписати її в межах закриття, щось на зразок цього

var 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, то, сподіваюсь, це буде деякою допомогою.

EDIT: Як зазначалося Бергі, є й інші можливі об'єкти, які можна вважати числовими, і було б краще білий список, ніж чорний список. З огляду на це я додам до критеріїв.

Я хочу, щоб моя функція 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(/^-/, ''));
}

Перевірте рішення

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('<option value="' + i + '">' + (i + 1) + '. ' + option + '</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());
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js" type="text/javascript"></script>
<script src="https://rawgit.com/Xotic750/testrunner-old/master/testrunner.js" type="text/javascript"></script>
<link href="https://rawgit.com/Xotic750/testrunner-old/master/testrunner.css" rel="stylesheet" type="text/css">
<h1>isNumber Test Cases</h1>

<h2 id="banner" class="pass"></h2>

<h2 id="userAgent">Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11</h2>

<div id="currentFunction"></div>

<div id="selectFunction">
  <label for="toTest" style="font-weight:bold; font-size:Large;">Select function to test:</label>
  <select id="toTest" name="toTest">
  </select>
</div>

<div id="testCode"></div>

<ol id="tests">
  <li class="pass">
    <strong>Integer Literals <b style="color:black;">(0, 10, 10)</b></strong>

    <ol style="display: none;">
      <li class="pass">Negative integer string</li>

      <li class="pass">Zero string</li>

      <li class="pass">Positive integer string</li>

      <li class="pass">Negative integer number</li>

      <li class="pass">Zero integer number</li>

      <li class="pass">Positive integer number</li>

      <li class="pass">Octal integer literal string</li>

      <li class="pass">Octal integer literal</li>

      <li class="pass">Hexadecimal integer literal string</li>

      <li class="pass">Hexadecimal integer literal</li>
    </ol>
  </li>

  <li class="pass">
    <strong>Foating-Point Literals <b style="color:black;">(0, 6, 6)</b></strong>

    <ol style="display: none;">
      <li class="pass">Negative floating point string</li>

      <li class="pass">Positive floating point string</li>

      <li class="pass">Negative floating point number</li>

      <li class="pass">Positive floating point number</li>

      <li class="pass">Exponential notation</li>

      <li class="pass">Exponential notation string</li>
    </ol>
  </li>

  <li class="pass">
    <strong>Non-Numeric values <b style="color:black;">(0, 18, 18)</b></strong>

    <ol style="display: none;">
      <li class="pass">Empty string: false</li>

      <li class="pass">Whitespace characters string: false</li>

      <li class="pass">Tab characters string: false</li>

      <li class="pass">Alphanumeric character string: false</li>

      <li class="pass">Non-numeric character string: false</li>

      <li class="pass">Boolean true literal: false</li>

      <li class="pass">Boolean false literal: false</li>

      <li class="pass">Number with preceding non-numeric characters: false</li>

      <li class="pass">Number with trailling non-numeric characters: false</li>

      <li class="pass">Undefined value: false</li>

      <li class="pass">Null value: false</li>

      <li class="pass">NaN value: false</li>

      <li class="pass">Infinity primitive: false</li>

      <li class="pass">Positive Infinity: false</li>

      <li class="pass">Negative Infinity: false</li>

      <li class="pass">Date object: false</li>

      <li class="pass">Empty object: false</li>

      <li class="pass">Instance of a function: false</li>
    </ol>
  </li>
</ol>

<div id="main">
  This page contains tests for a set of isNumber functions. To see them, take a look at the source.
</div>

<div>
  <p class="result">Tests completed in 0 milliseconds.
    <br>0 tests of 0 failed.</p>
</div>


37



Це, на мій погляд, є найбільш захищеною функцією; останній. Прийнята відповідь охоплює, мабуть, 99,99% випадків, але це, мабуть, 100% випадків з невеликими накладними витратами. - Samuel
Ви забули про буквальному значенні "99 999" точок з тону. Це дійсне число у всій Європі, окрім Великобританії - Andrii Horda
Не було забувалося, що це не те, що я вважав числовим у сенсі номерів Javascript, також ОП IsNumeric('99,999') => false - Xotic750


Так, вбудований isNaN(object) буде набагато швидше, ніж будь-який синтаксичний аналіз регулярного виразу, тому що він вбудований і складений, а не інтерпретується на льоту.

Хоча результати дещо відрізняються від того, що ви шукаєте (Спробуй це):

                                              // IS NUMERIC
document.write(!isNaN('-1') + "<br />");      // true
document.write(!isNaN('-1.5') + "<br />");    // true
document.write(!isNaN('0') + "<br />");       // true
document.write(!isNaN('0.42') + "<br />");    // true
document.write(!isNaN('.42') + "<br />");     // true
document.write(!isNaN('99,999') + "<br />");  // false
document.write(!isNaN('0x89f') + "<br />");   // true
document.write(!isNaN('#abcdef') + "<br />"); // false
document.write(!isNaN('1.2.3') + "<br />");   // false
document.write(!isNaN('') + "<br />");        // true
document.write(!isNaN('blah') + "<br />");    // false

30