От автора: В данной статье мы познакомимся со специальным свойством NaN (Not-A-Number), которое является значением, представляющим не-число.
Тип числа в JavaScript содержит целые числа и числа с плавающей запятой:
const integer = 4; const float = 1.5; typeof integer; // => ‘number’ typeof float; // => ‘number’ |
Плюс есть два специальных числовых значения: Infinity (число больше, чем любое другое число) и NaN (представляющее концепцию «не число»):
Профессия Frontend-разработчик PRO
Готовим Frontend-разработчиков с нуля
На курсе вы научитесь создавать интерфейсы веб-сервисов с помощью языков программирования и
дополнительных технологий. Сможете разрабатывать планировщики задач, мессенджеры, интернет-магазины…
Узнать подробнее
До 10 проектов в портфолио для старта карьеры
Подходит для новичков без опыта в программировании
Практика на вебинарах с разработчиками из крупных компаний
const infinite = Infinity; const faulty = NaN; typeof infinite; // => ‘number’ typeof faulty; // => ‘number’ |
Хотя непосредственная работа с NaN редко встречается, оно может неожиданно появиться после неудачной операции с числами.
Давайте подробно рассмотрим специальное значение NaN: как проверить, содержит ли переменная NaN, и сценарии, которые в которых генерируется значения «не число».
1. Число NaN
Тип числа в JavaScript — это набор всех числовых значений, включая «не число», положительную бесконечность и отрицательную бесконечность.
«Not A Number» можно получить с помощью специального выражения NaN или как свойство глобального объекта или функции Number:
typeof NaN; // => ‘number’ typeof window.NaN; // => ‘number’ typeof Number.NaN; // => ‘number’ |
«Не число» — это значение, которое не представляет действительное число, несмотря на то, что оно имеет тип числа. Через NaN полезно представлять ошибочные операции с числами. Например, умножение числа на undefined не является допустимой операцией, поэтому дает NaN:
Также попытка разобрать недопустимую числовую строку, например, ‘Joker’ приводит к NaN:
parseInt(‘Joker’, 10); // => NaN |
2. Проверка на равенство с NaN
Интересным свойством NaN является то, что оно не равно ни одному значению, даже самому себе:
Это поведение полезно для определения, является ли переменная NaN:
const someNumber = NaN; if (someNumber !== someNumber) { console.log(‘Is NaN’); } else { console.log(‘Is Not NaN’); } // logs «Is NaN» |
Выражение someNumber !== someNumber равно true, только если someNumber является NaN. Таким образом, приведенный выше фрагмент регистрирует в консоли «Is NaN». JavaScript содержит встроенные функции для определения NaN: isNaN() и Number.isNaN():
isNaN(NaN); // => true isNaN(1); // => false Number.isNaN(NaN); // => true Number.isNaN(1); // => false |
Разница между этими функциями заключается в том, что Number.isNaN() не преобразуется свой аргумент в число:
isNaN(‘Joker12’); // => true Number.isNaN(‘Joker12’); // => false |
isNaN(‘Joker12’) преобразует аргумент ‘Joker12’ в число, которое является NaN. Таким образом, функция возвращает true.
С другой стороны, Number.isNaN(‘Joker12’) проверяет аргумент без преобразования. Функция возвращает false, потому ‘Joker12’ не равно NaN.
3. Операции, дающие NaN
3.1 Парсинг чисел
В JavaScript вы можете преобразовать числовые строки в числа. Например, вы можете легко преобразовать строку ‘1.5’ в число с плавающей запятой 1.5:
const numberString = ‘1.5’; const number = parseFloat(numberString); number; // => 1.5 |
Когда строка не может быть преобразована в число, функция синтаксического анализа возвращает NaN: указывая, что синтаксический анализ не выполнен. Вот некоторые примеры:
parseFloat(‘Joker12.5’); // => NaN parseInt(‘Joker12’, 10); // => NaN Number(‘Joker12’); // => NaN |
При парсинге чисел рекомендуется проверить, не является ли результат парсинга NaN:
let inputToParse = ‘Invalid10’; let number; number = parseInt(inputToParse, 10); if (isNaN(number)) { number = 0; } number; // => 0 |
Парсинг inputToParse не удался, поэтому parseInt(inputToParse, 10) возвращается NaN. Условие if (isNaN(number)) оценивается, как true, и 0 назначается number.
3.2 undefined в качестве операнда
При использовании undefined в качестве операнда в арифметических операциях, таких как сложение, умножение и т д. мы получаем NaN. Например:
function getFontSize(style) { return style.fontSize; } const fontSize = getFontSize({ size: 16 }) * 2; const doubledFontSize = fontSize * 2; doubledFontSize; // => NaN |
getFontSize() — это функция, которая обращается к свойству fontSize из объекта стиля. При вызове getFontSize({ size: 16 }) результатом будкт undefined (свойство fontSize не существует в объекте { size: 16 }). fontSize * 2 оценивается как undefined * 2, что дает NaN.
«Not A Number» генерируется, когда в качестве значения в арифметических операциях используется отсутствующее свойство или функция, возвращающая undefined. Отсутствие undefined в арифметических операциях — это хороший способ предотвратить получение NaN.
3.3 NaN как операнд
Значение NaN также генерируется, когда операндом в арифметических операциях является NaN:
1 + NaN; // => NaN 2 * NaN; // => NaN |
NaN распространяется на арифметические операции:
let invalidNumber = 1 * undefined; let result = 1; result += invalidNumber; // appendresult *= 2; // duplicate result++; // increment result; // => NaN |
Операции с переменной result прерываются после добавления к result значения invalidNumber (которое является NaN).
3.4 Неопределенные формы
Значение NaN создается, когда арифметические операции имеют неопределенные формы. Деление 0 / 0 и Inifinity / Infinity:
0 / 0; // => NaN Infinity / Infinity; // => NaN |
Умножение 0 и Infinity:
Сложение бесконечных чисел с разными знаками:
—Infinity + Infinity; // => NaN |
3.5 Неверные аргументы математических функций
Квадратный корень из отрицательного числа:
Math.pow(—2, 0.5); // => NaN (—2) ** 0.5; // => NaN |
Или логарифм отрицательного числа:
4. Заключение
Понятие «не число», выраженное в JavaScript с помощью NaN, полезно для представления ошибочных операций над числами. NaN не равно ни одному значению, даже самому себе. Рекомендуемый способ проверить, содержит ли переменная NaN — использовать Number.isNaN(value).
Преобразование числовых строк в числа, в случае неудачи может дать NaN. Рекомендуется проверять, не возвращают ли parseInt(), parseFloat() или Number() NaN.
Если undefined или NaN используются в качестве операнда в арифметических операциях, это обычно приводит к NaN. Правильная обработка undefined (предоставление значений по умолчанию для отсутствующих свойств) является рекомендованным подходом для предотвращения этой ситуации.
Неопределенные формы или недопустимые аргументы для математических функций также приводят получению NaN. Но это случается редко. Вот мой практический совет: «Получили NaN? Ищите undefined!»
Автор: Dmitri Pavlutin
Источник: //dmitripavlutin.com
Профессия Frontend-разработчик PRO
Готовим Frontend-разработчиков с нуля
На курсе вы научитесь создавать интерфейсы веб-сервисов с помощью языков программирования и
дополнительных технологий. Сможете разрабатывать планировщики задач, мессенджеры, интернет-магазины…
Узнать подробнее
До 10 проектов в портфолио для старта карьеры
Подходит для новичков без опыта в программировании
Практика на вебинарах с разработчиками из крупных компаний
Редакция: Команда webformyself.
Some definitions from W3Schools:
Infinity: A numeric value that represents positive/negative infinity
The POSITIVE_INFINITY property represents infinity, returned on overflow.
NEGATIVE_INFINITY, represents negative infinity (returned on overflow).
The NaN property represents «Not-a-Number» value. This property indicates that a value is not a legal number.
The isFinite() function determines whether a number is a finite, legal number.
This function returns false if the value is +infinity, -infinity, or NaN.
Some tests:
var n1 = 1/0;
var n2 = 0/0;
var n3 = (Number.MAX_VALUE)*2; //overflow
var b1 = Number.POSITIVE_INFINITY == n1;
var b2 = Number.POSITIVE_INFINITY == n2;
var b2n = Number.NEGATIVE_INFINITY == n2;
var b3 = Number.POSITIVE_INFINITY == n3;
var msg = "n1=" + n1 + ", n2=" + n2 + ", n3=" + n3;
msg += "<br/> n1 Is POSITIVE_INFINITY=" + b1;
msg += "<br/> n2 Is POSITIVE_INFINITY=" + b2;
msg += "<br/> n2 Is POSITIVE_INFINITY=" + b2n;
msg += "<br/> n3 Is POSITIVE_INFINITY=" + b3;
msg += "<br/> n1 IsFinite=" + isFinite(n1);
msg += "<br/> n2 IsFinite=" + isFinite(n2);
msg += "<br/> n3 IsFinite=" + isFinite(n3);
msg += "<br/> n1 + n1 =" + (n1 + n1) ;
msg += "<br/> n1 - n1 =" + (n1 - n1) ;
msg += "<br/> n2 + n1 =" + (n2 + n1) ;
document.write(msg);
Shows
n1=Infinity, n2=NaN, n3=Infinity
n1 Is POSITIVE_INFINITY=true
n2 Is POSITIVE_INFINITY=false
n2 Is POSITIVE_INFINITY=false
n3 Is POSITIVE_INFINITY=true
n1 IsFinite=false
n2 IsFinite=false
n3 IsFinite=false
n1 + n1 =Infinity
n1 - n1 =NaN
n1 - n1 =NaN
Have you ever wondered what is NaN
error coming in your project? 🤔
Today, in this article I am going to discuss the NaN
error in detail.
Let’s get started 🚀
In JavaScript, NaN stands for Not a Number.
This error occurs when you parse something to a number that is not a number
Let’s see it with an example,
var helloWorld = parseInt(helloWorld);
Enter fullscreen mode
Exit fullscreen mode
This will return NaN
didn’t get it? No problem let’s get a little simpler
var helloWorld = parseInt("Hello World");
Enter fullscreen mode
Exit fullscreen mode
"Hello World"
is a string
and we are parsing to an integer but that is not possible therefore the browser will return NaN
isNan()
Method
isNan()
will return true if a value is NaN
isNaN(18)
// false
isNaN(18.81)
// false
isNaN("JavaScript")
// true
isNaN("233.3")
// false
isNaN('17/01/2022')
// true
Enter fullscreen mode
Exit fullscreen mode
As you can see numbers
will return false as they are not NaN even if, the number is in the form of string
.
Any string (word or sentence) will return true as it is NaN
Me when isNaN("123")
showing false:
What about you? Comment 👇
Here comes, something that contradicts
As discussed earlier, isNan()
will return true if a value is Not-a-Number(NaN)
Number.isNaN()
method while is completely opposite of isNaN
method, here Number.isNaN()
will return true
if number is NaN
Let’s go with an example,
isNaN('JavaScript')
// true
Number.isNaN('JavaScript')
// false
Enter fullscreen mode
Exit fullscreen mode
isNaN(18)
// false
Number.isNaN(18)
// true
Enter fullscreen mode
Exit fullscreen mode
Thank you for reading, have a nice day!
- Follow me on Twitter — @codewithsnowbit
- Subscribe me on YouTube — Code With SnowBit
Время на прочтение
6 мин
Количество просмотров 145K
Мне очень нравится JavaScript и я считаю его мощным и удобным. Но для большинства начинающих JS-программистов, много проблем создаёт недопонимание аспектов языка. Часто конструкции языка ведут себя «нелогично». В данной статье я хочу привести примеры «граблей», на которые я наступил; объяснить поведение языка и дать пару советов.
Типы
Как написано в спецификации ECMAScript, всего существует 6 типов:
- Undefined
- Null
- Boolean
- String
- Number
- Object
Все значения должны принадлежать к ним. В JS есть оператор typeof, который, как казалось бы, должен возвращать тип объекта. Казалось бы, один из перечисленных. Что получается на самом деле:
typeof 5; //"number", ок, похоже на правду
typeof "hello"; //"string"
typeof true; //"boolean"
typeof undefined; //"undefined"
typeof {}; //"object". Пока 5 из 5
typeof null; //"object". WTF?
typeof function(){}; //"function". Разве у нас есть тип function?
Проблема: несмотря на то, что тип у null — Null, оператор возвращает ‘object’; а тип у функции — Object, оператор возвращает ‘function’, а такого типа нет.
Объяснение: typeof возвращает не тип, а строку, которая зависит от аргумента и не является именем типа.
Совет: забудьте про типы. Серьезно, я считаю что знание 6 типов JS не даст вам пользы, а оператор typeof используется довольно часто, поэтому лучше запомнить результаты его работы:
Тип аргумента | Результат |
Undefined | undefined |
Null | object |
Boolean | boolean |
Number | number |
String | string |
Object (результаты оператора new, inline-объекты ({key: value})) | object |
Object (функции) | function |
Магические значения: undefined, null, NaN
В спецификации описаны так:
- undefined value — primitive value used when a variable has not been assigned a value
- Undefined type — type whose sole value is the undefined value
- null value — primitive value that represents the intentional absence of any object value
- Null type — type whose sole value is the null value
- NaN — number value that is a IEEE 754 “Not-a-Number” value
У себя в голове я держу следующее:
- undefined — значение переменной, которая не была инициализирована. Единственное значение типа Undefined.
- null — умышленно созданный «пустой» объект. Единственное значение типа Null.
- NaN — специальное значение типа Number, для выражения «не чисел», «неопределенности». Может быть получено, например, как результат деления 0 на 0 (из курса матанализа помним, что это неопределенность, а деление других чисел на 0 — это бесконечность, для которой в JS есть значения Infinity).
С этими значениями я обнаружил много «магии». Для начала, булевы операции с ними:
!!undefined; //false
!!NaN; //false
!!null; //false
//как видим, все 3 значения при приведении к boolean дают false
null == undefined; //true
undefined === undefined; //true
null === null; //true
NaN == undefined; //false
NaN == null; //false
NaN === NaN; //false!
NaN == NaN; //false!
Проблема: с чем бы мы ни сравнивали NaN, результатом сравнения всегда будет false.
Объяснение: NaN может возникать в результате множества операций: 0/0, parseInt(‘неприводимая к числу строка’), Math.sqrt(-1) и было бы странно, если корень из -1 равнялся 0/0. Именно поэтому NaN !== NaN.
Совет: не использовать булевы операторы с NaN. Для проверки нужно использовать функцию isNaN.
typeof a; //'undefined'
a; //ReferenceError: a is not defined
Проблема: оператор typeof говорит нам, что тип необъявленной переменной — undefined, но при обращении к ней происходит ошибка.
Объяснение: на самом деле, есть 2 понятия — Undefined и Undeclared. Так вот, необъявленная переменная является Undeclared-переменной и обращение к ней вызывает ошибку. Объявленная, но не инициализированная переменная принимает значение undefined и при обращении к ней ошибок не возникает.
Совет: перед обращением к переменной, вы должны быть уверенны, что она объявлена. Если вы обратитесь к Undeclared-переменной, то код, следующий за обращением, не будет выполнен.
var a; //вновь объявленная переменная, для которой не указано значение, принимает значение undefined
console.log(undefined); //undefined
console.log(a); // undefined
a === undefined; //true
undefined = 1;
console.log(undefined); //1
a === undefined; //false
Проблема: в любой момент мы можем прочитать и записать значение undefined, следовательно, кто-то может перезаписать его за нас и сравнение с undefined будет некорректным.
Объяснение: undefined — это не только значение undefined типа Undefined, но и глобальная переменная, а значит, любой может её переопределить.
Совет: просто сравнивать переменные с undefined — плохой тон. Есть 3 варианта решения данной проблемы, для создания «пуленепробиваемого» кода.
- Вы можете сравнивать не значение переменной, а её тип: «typeof a === ‘undefined’».
- Использовать паттерн immediately-invoked function:
(function(window, undefined){
//т.к. второй аргумент не был передан, значение переменной undefined будет «правильным».
}(this));
- Для получения реального «undefined»-значения можно использовать оператор void (кстати, я не знаю другого применения этому оператору):
typeof void(0) === 'undefined' // true
Теперь попробуем совершить аналогичные действия с null:
console.log(null); //null
null = 1; //ReferenceError: Invalid left-hand side in assignment
Проблема: несмотря на некоторые сходства между null и undefined, null мы перезаписать не можем. На самом деле проблема не в этом, а в том, что язык ведёт себя нелогично: даёт перезаписать undefined, но не даёт перезаписать null.
Объяснение: null — это не глобальная переменная и вы не можете её создать, т. к. null — зарезервированное слово.
Совет: в JavaScript не так много зарезервированных слов, проще их запомнить и не использовать как имена переменных, чем вникать, в чём проблема, когда она возникнет.
И теперь сделаем тоже самое с NaN:
console.log(NaN); //NaN
NaN = 1;
console.log(NaN); //NaN
isNaN(NaN); //true
Проблема: при переопределении undefined всё прошло успешно, при переопределении null возникла ошибка, а при переопределении NaN операция не вызвала ошибки, но свойство не было переопределено.
Объяснение: нужно понимать, что NaN — переменная глобального контекста (объекта window). Помимо этого, к NaN можно «достучаться» через Number.NaN. Но это неважно, ниодно из этих свойств вы не сможете переопределить, т. к. NaN — not writable property:
Object.getOwnPropertyDescriptor(window, NaN).writable; //false
Object.getOwnPropertyDescriptor(Number, NaN).writable; //false
Совет: как JS-программисту, вам нужно знать об атрибутах свойств:
Атрибут | Тип | Смысл |
enumerable | Boolean | Если true, то данное свойство будет участвовать в циклах for-in |
writable | Boolean | Если false, то значение этого свойства нельзя будет изменить |
configurable | Boolean | Если false, то значение этого свойства нельзя изменить, удалить и изменить атрибуты свойства тоже нельзя |
value | Любой | Значение свойства при его чтении |
get | Object (или Undefined) | функция-геттер |
set | Object (или Undefined) | функция-сеттер |
Вы можете объявлять неудаляемые или read-only свойства и для созданных вами объектов, используя метод Object.defineProperty:
var obj = {};
Object.defineProperty(obj, 'a', {writable: true, configurable: true, value: 'a'});
Object.defineProperty(obj, 'b', {writable: false, configurable: true, value: 'b'});
Object.defineProperty(obj, 'c', {writable: false, configurable: false, value: 'c'});
console.log(obj.a); //a
obj.a = 'b';
console.log(obj.a); //b
delete obj.a; //true
console.log(obj.b); //b
obj.b = 'a';
console.log(obj.b); //b
delete obj.b; //true
console.log(obj.c); //c
obj.b = 'a';
console.log(obj.c); //c
delete obj.b; //false
Работа с дробными числами
Давайте вспомним 3-й класс и сложим несколько десятичных дробей. Результаты сложения в уме проверим в консоли JS:
0.5 + 0.5; //1
0.5 + 0.7; //1.2
0.1 + 0.2; //0.30000000000000004;
0.1 + 0.7; //0.7999999999999999;
0.1 + 0.2 - 0.2; //0.10000000000000003
Проблема: при сложении некоторых дробных чисел, выдаётся арифметически неверный результат.
Объяснение: такие результаты получаются из-за особенностей работы c числами с плавающей точкой. Это не является особенностью JavaScript, другие языки работают также (я проверил в PHP, Python и Ruby).
Совет: во-первых, вы, как программист, обязаны знать об особенностях работы компьютера с числами с плавающей точкой. Во-вторых, в большинстве случаев достаточно просто округлять результаты. Но, если вдруг необходимо выдавать пользователю точный результат, например, при работе с данными о деньгах, вы можете просто умножать все аргументы на 10 и результат делить обратно на 10, например так:
function sum() {
var result = 0;
for (var i = 0, max = arguments.length; i< max; i++ ) {
result += arguments[i]*10;
}
return result / 10;
}
sum(0.5, 0.5); //1
sum(0.5, 0.7); //1.2
sum(0.1, 0.2); //0.3
sum(0.1, 0.7); //0.8
sum(0.1, 0.2, -0.2); //0.1
Вывод
Это только несколько необычных примеров с непредсказуемым результатом. Если помнить о них, то получится не наступить на те же грабли и быстро понять, в чём проблема. Если найдёте новый «нелогичный» кусок кода, то попробуйте осознать, что происходит с точки зрения языка, почитав спецификацию или MDN.
Глобальное свойство NaN
— это значение, представляющее Not-A-Number.
Атрибуты свойства NaN
|
|
---|---|
Writable | no |
Enumerable | no |
Configurable | no |
Try it
Description
NaN
— это свойство глобального объекта . Другими словами, это переменная в глобальной области видимости.
Начальное значение NaN
равно Not-A-Number — то же, что и значение Number.NaN
. В современных браузерах NaN
является ненастраиваемым и недоступным для записи свойством. Даже если это не так, избегайте переопределения. NaN
в программе довольно редко .
Существует пять различных типов операций, возвращающих NaN
:
- Число не может быть проанализировано (например,
parseInt("blabla")
илиNumber(undefined)
) - Математическая операция, результат которой не является действительным числом (например,
Math.sqrt(-1)
) - Операнд аргумента —
NaN
(например,7 ** NaN
) - Неопределенная форма (например,
0 * Infinity
илиundefined + undefined
) - Любая операция, которая включает строку и не является операцией сложения (например,
"foo" / 3
)
Examples
Тестирование против NaN
NaN
сравнивает unequal (через ==
, !=
, ===
и !==
) с любым другим значением, в том числе с другим значением NaN
. Используйте Number.isNaN()
или isNaN()
, чтобы наиболее четко определить, является ли значение NaN
. Или выполните самосравнение: NaN
и только NaN
будут сравниваться неравно самому себе.
NaN === NaN; Number.NaN === NaN; isNaN(NaN); isNaN(Number.NaN); Number.isNaN(NaN); function valueIsNaN(v) { return v !== v; } valueIsNaN(1); valueIsNaN(NaN); valueIsNaN(Number.NaN);
Однако обратите внимание на разницу между isNaN()
и Number.isNaN()
: первый вернет true
если значение в настоящее время равно NaN
, или если оно будет NaN
после приведения его к числу, а последнее вернет true
только если значение в настоящее время NaN
:
isNaN('hello world'); Number.isNaN('hello world');
По той же причине использование значения bigint
вызовет ошибку с isNaN()
, а не с Number.isNaN()
:
isNaN(1n); Number.isNaN(1n);
Кроме того, некоторые методы массива не могут найти NaN
, а другие -.
const arr = [2, 4, NaN, 12]; arr.indexOf(NaN); arr.includes(NaN); arr.findIndex((n) => Number.isNaN(n));
Specifications
Browser compatibility
Desktop | Mobile | Server | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Chrome | Edge | Firefox | Internet Explorer | Opera | Safari | WebView Android | Chrome Android | Firefox для Android | Opera Android | Safari на IOS | Samsung Internet | Deno | Node.js | |
NaN |
1 |
12 |
1 |
4 |
4 |
1 |
4.4 |
18 |
4 |
10.1 |
1 |
1.0 |
1.0 |
0.10.0 |
See also
Number.NaN
Number.isNaN()
isNaN()
JavaScript
-
Math.tanh()
Функция Math.tanh()возвращает гиперболический тангенс числа,то есть tanh x sinh cosh e 2 1 frac{sinh x}{cosh {e^x frac{e^{2x}1}{e^{2x}+1}Число.
-
Math.trunc()
Функция Math.trunc()возвращает целую часть числа,удаляя все дробные цифры.
-
Number
Number-это примитивный объект-обертка,используемый для представления и манипулирования числами,такими как 37 -9.25.
-
Number.EPSILON
Свойство Number.EPSILON представляет разницу между 1 и наименьшим значением с плавающей точкой больше чем Вы не должны создавать объект Number для доступа к этому свойству.