Как быстро проверить число на NaN
Опубликовал root в блоге JavaScript 04 февраля 2010, 07:08
Сегодня копался в коде jQuery и обратил внимание на то каким образом осуществляется проверка числа на NaN. Вместо того, чтобы использовать стандартную функцию isNaN() Johng Resig преобразует число к строке и сравнивает его со строкой 'NaN'.
Я подумал, что раз используется такой странный способ, то тому есть свое логическое объяснение. Первое, что пришло мне на ум — выигрыш в скорости, но как оказалось это совершенно не так.
Для проверки я написал простенький скрипт:
Чтобы не заморачиваться на измерение скорости средствами JavaScript использовал профилирование встроенное в плагин FireBug.
После проведение замеров FireBug показал следующее:
Получается, что isNaN работает быстрее более чем в два раза!
Ради справедливости стоит отметить, что в других браузерах результаты могут быть иными, возможно даже в более старой версии FireFox-а выигрыш будет на стороне toString(). Но в FireFox 3.6 ситуация такая как я описал выше.
Если кто-то может привести данные о времени работы аналогичного кода для Оперы и IE милости прошу отписаться в комментариях.
Из сказанного выше, можно сделать вывод, что для работы в FireFox лучше использовать функцию isNaN. Но значит ли, что не существует другого более быстрого способа проверить число на NaN?
Чтобы ответить на данный вопрос, я решил провести еще пару экспериментов.
Первое, что пришло мне на ум — это изменить способ перевода числа в строку, для этого я заменил код n.toString() == 'NaN' на n + '' === 'NaN'; в результате функция b(); стала выполняться на 5мс быстрее. Но функция isNaN() все равно работала значительно лучше.
Второе решение, я нашел в интернете и заключается оно в том, чтобы проверить равно ли число само себе, а точнее не равно ли оно само себе:
Я уже писал одно из которых заключается в том, что NaN не равно самому себе, таким образом сравнение n != n будет истинным только в случае когда n равно NaN.
Чтобы проверить указанный метод. Я заменил проверку toString() на n != n и запустил профилирование повторно. В результате были получены следующие значения:
Таким образом, на сегодняшний день самый быстрый способ (известный мне) проверить число на значение NaN — это выполнить проверку n != n.
Я подумал, что раз используется такой странный способ, то тому есть свое логическое объяснение. Первое, что пришло мне на ум — выигрыш в скорости, но как оказалось это совершенно не так.
Для проверки я написал простенький скрипт:
function a() {
for (var i = 0; i < 100000; i++) {
var n = parseInt('AAAA');
isNaN(n); // true
}
}
function b() {
for (var i = 0; i < 100000; i++) {
var n = parseInt('AAAA');
'NaN' == n.toString() ; // true
}
}
a();
b();
Чтобы не заморачиваться на измерение скорости средствами JavaScript использовал профилирование встроенное в плагин FireBug.
После проведение замеров FireBug показал следующее:
функция b() — 32 мс
функция a() -13 мс.
Получается, что isNaN работает быстрее более чем в два раза!
Ради справедливости стоит отметить, что в других браузерах результаты могут быть иными, возможно даже в более старой версии FireFox-а выигрыш будет на стороне toString(). Но в FireFox 3.6 ситуация такая как я описал выше.
Если кто-то может привести данные о времени работы аналогичного кода для Оперы и IE милости прошу отписаться в комментариях.
Из сказанного выше, можно сделать вывод, что для работы в FireFox лучше использовать функцию isNaN. Но значит ли, что не существует другого более быстрого способа проверить число на NaN?
Чтобы ответить на данный вопрос, я решил провести еще пару экспериментов.
Первое, что пришло мне на ум — это изменить способ перевода числа в строку, для этого я заменил код n.toString() == 'NaN' на n + '' === 'NaN'; в результате функция b(); стала выполняться на 5мс быстрее. Но функция isNaN() все равно работала значительно лучше.
Второе решение, я нашел в интернете и заключается оно в том, чтобы проверить равно ли число само себе, а точнее не равно ли оно само себе:
var n = parseInt('AAAA');
n != n // true
Я уже писал одно из которых заключается в том, что NaN не равно самому себе, таким образом сравнение n != n будет истинным только в случае когда n равно NaN.
Чтобы проверить указанный метод. Я заменил проверку toString() на n != n и запустил профилирование повторно. В результате были получены следующие значения:
функция a() — 13 мс
функция b() — 8 мс (!)
Таким образом, на сегодняшний день самый быстрый способ (известный мне) проверить число на значение NaN — это выполнить проверку n != n.
JavaScript. Грабли с NaN
Опубликовал root в блоге JavaScript 28 января 2010, 06:04
Программируя на javascript никогда не знаешь когда встанешь на очередную граблю. Иногда складывается впечатление, что в языке больше плохого чем, хорошего.
Например, в JS есть такое значение — NaN расшифровывается как Not A Number. Обычно это значение возвращается при ошибке выполнения операций с числами.
В данном примере, при выполнении первой операции функция parseInt не смогла преобразовать строку в число и поэтому вернула значения NaN. А вот в 3-ей строке, все прошло успешно, что кажется мне не совсем логичным.
Другие фокусы, которые выкидывает JavaScript хорошо демонстрирует следующий пример:
Получается, что NaN не равен сам себе, одновременно NaN не больше и не меньше самого себя. А если запросить его тип, то оказывается, что это число. Непонятно, почему тогда не работают операции сравнения.
Плохо в данной ситуации то, что код который многим кажется вполне рабочим, на самом деле таковым не является:
Причина, в том, что сравнение a == NaN || b == NaN — всегда будет возвращать false, даже если a или b будут иметь значение NaN.
Для того, чтобы узнать содержит ли переменная значение NaN используется функция isNaN:
Чтобы избежать проблем со значением NaN я использую собственную функцию определения является ли переменная числом:
Например, в 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);
}