JavaScript. Грабли с NaN 
Программируя на javascript никогда не знаешь когда встанешь на очередную граблю. Иногда складывается впечатление, что в языке больше плохого чем, хорошего.
Например, в JS есть такое значение — NaN расшифровывается как Not A Number. Обычно это значение возвращается при ошибке выполнения операций с числами.
parseInt('AAAA'); // NaN parseInt('1'); // 1 parseInt('16 somthing else'); // 16 — неожиданно, правда?
В данном примере, при выполнении первой операции функция parseInt не смогла преобразовать строку в число и поэтому вернула значения NaN. А вот в 3-ей строке, все прошло успешно, что кажется мне не совсем логичным.
Другие фокусы, которые выкидывает JavaScript хорошо демонстрирует следующий пример:
NaN == NaN; // false NaN != NaN; // true NaN > NaN; // false NaN < NaN; // false typeof NaN === 'number'; // true
Получается, что NaN не равен сам себе, одновременно NaN не больше и не меньше самого себя. А если запросить его тип, то оказывается, что это число. Непонятно, почему тогда не работают операции сравнения.
Плохо в данной ситуации то, что код который многим кажется вполне рабочим, на самом деле таковым не является:
function sum(a, b) { a = parseInt(a, 10); b = parseInt(b, 10); if (a == NaN || b == NaN) { alert('Ошибка'); return 0; } return a+b; } sum('1', 'bbbb'); // NaN
Причина, в том, что сравнение a == NaN || b == NaN — всегда будет возвращать false, даже если a или b будут иметь значение NaN.
Для того, чтобы узнать содержит ли переменная значение NaN используется функция isNaN:
isNaN(NaN); // true isNaN('AAAA'); // true isNaN('0'); // false
Чтобы избежать проблем со значением NaN я использую собственную функцию определения является ли переменная числом:
function isNum(v) { return typeof v === 'number' && isFinite(v); }
подписаться на блог
Лучшие комментарии
Evgeny Sergeev
Веб-разработчик, автор блога codeart.ru
Вот еще один забавный пример:
parseInt(’Five Dollars’,16);
Кто догадается что выдаст функция?
Nick
Гость
А, по-моему, всё предельно ясно если знать основы языка.
Просто нужно понимать, что такое NaN и знать о существовании функции isNaN, и тогда включается свет в этой тёмной комнате!
Куда интереснее пример:
var f = function()
{
return
{
a:1
};
}
alert(typeof f());
что вернёт?
тут нужно куда глубже знания особенностей языка
Сергей Шепелев
Гость
> Получается, что NaN не равен сам себе, одновременно NaN не больше и не меньше самого себя. А если запросить его тип, то оказывается, что это число. Непонятно, почему тогда не работают операции сравнения.
Они, как раз, работают. А возвращают false потому что нет способа определить, что один NaN больше другого. Тут бы, конечно, следовало ошибку кинуть или вернуть null какой-нибудь. false это у них просто “дефолтное значение” как бы. Получается, что на false в сравнениях чисел нельзя ориентироваться, можно только на true.
Evgeny Sergeev
Веб-разработчик, автор блога codeart.ru
Сергей, мне кажется, что все же лучше сначала убедиться, что функция не вернуло значение NaN, а уже потом сравнивать.
Хотя, конечно, в большинстве случаев “истина” более информативно чем “ложь”.
BlackApricot
Гость
parseInt(’16 somthing else’); // 16 — неожиданно, правда?
А что здесь неожиданное? функция для этого и предназначена, преобразовать строку в число.
Логика простая, берём все цифры в строке, от начала и до первого символа “не цифра”.
Тормоз
Гость
Тоже сейчас столкнулся с этим, причём вообще непонятно откуда это NaN взялось, число там! Странно, странно. С гугла к тебе пришёл ) Кое-что прояснилось, спасибо.
OLEGator
Гость
if(parseInt($(this).val())+”_” != “NaN_”)
Ivan
Гость
автор пишет: parseInt(’16 somthing else’); // 16 — неожиданно, правда?
Автор, вы как рах ХОРОШЕЕ приняли тут за “плохое”.
лично мне кажется прозрачным то… что метод выполняется. Потому что JS создан для работы с HTML. А в HTML у нас какие цифровые значения? Это всегда - ПИКСЕЛИ. Так вот… если мы в качестве аргумента в функцию передадим строчку “10px”… чтобы затем выделывать с ней мат.преобразования… то не нужно заморачиваться на отсечение “px”. Функция всё сделала за вас и уменьшила Вам работку.
Evgeny Sergeev
Веб-разработчик, автор блога codeart.ru
Вот еще один забавный пример:
parseInt(’Five Dollars’,16);
Кто догадается что выдаст функция?
Solovyov A.A.
Гость
to Evgeny Sergeev:
Забавно. Стало интересно - полез смотреть =)
Возвращает 0xF в десятичной системе исчисления.
Kenter
Гость
2 Solovyov A.A.
0xF - это не десятичная, а шестнадцатиричная. Все правильно возвращает - перекодирует первый символ (F) по основанию 16.
Nick
Гость
А, по-моему, всё предельно ясно если знать основы языка.
Просто нужно понимать, что такое NaN и знать о существовании функции isNaN, и тогда включается свет в этой тёмной комнате!
Куда интереснее пример:
var f = function()
{
return
{
a:1
};
}
alert(typeof f());
что вернёт?
тут нужно куда глубже знания особенностей языка
Evgeny Sergeev
Веб-разработчик, автор блога codeart.ru
Nick, про Semicolon insertion я уже писал - http://www.codeart.ru/2010/01/25/podvodnye-kamni-javascript-ili-opasnoe-svojstvo-semicolon-insertion/
По поводу “если знать основы языка”, язык должен быть максимально прозрачным, так как изучение языка - это не цель, а средство.
Leave a Reply