Какой тип числа у Number в JS?

633a1b93f0b6a413e59ea4cd832b393f.jpg

Если вы изучали языки со строгой типизацией, то должны понимать, что определённое значение должно храниться в памяти с заранее выделенным для неё количеством байт. Например, для числа int выделяется 4 байта, что равняется 32 битам и может содержать в себе 2³² значений, это значит мы можем выразить в десятичной системе исчисления от -2 147 483 647 до 2 147 483 647. Какой же тип числа используется в JS?

В стандарте EcmaScript написано, что Number Value: primitive value corresponding to a double-precision 64-bit binary format IEEE 754 value. То есть число double (число двойной точности), занимающее 8 байт = 64 бита (из них 1 бит выделен для обозначения знака числа, 11 бит для порядка и 52 — мантисса, всё что идёт после запятой).

Выделение битов для представления числа doubleВыделение битов для представления числа double

Диапазон значений: 1,7E +/- 308 (15 знаков). Вы можете проверить и посмотреть это число полностью, выведя в консоли максимальное допустимое число объекта Number:  Number.MAX_VALUE.Вот ссылка на стандарт IEEE754:  https://en.wikipedia.org/wiki/IEEE_754Если выйти за пределы этого числа, то Number выдаст нам значение Infinity.

Максимальное значение double с плавающей запятойМаксимальное значение double с плавающей запятой

Хорошо, но сколько же целых чисел можно выразить с помощью double?
Ответ: 9,007,199,254,740,991 или~9 квадрильонов. Все числа до этого числа являются безопасными, что значит их можно сравнивать между собой. Данное максимально безопасное число также можно получить используя объект Number:  Number.MAX_SAFE_INTEGER.

Чтобы проверить, что числа действительно сравниваются не правильно, можно выполнить в консоли:

Сравнение чисел, которые больше максимально допустимого целого числа. Математически это не равные значения, однако нам вернётся true.Сравнение чисел, которые больше максимально допустимого целого числа. Математически это не равные значения, однако нам вернётся true.

Если вам нужно работать с большими числами и сравнивать их между собой, то можно проверять является ли число безопасным с помощью метода isSafeInteger():

Проверка является ли число безопаснымПроверка является ли число безопасным

Хорошо, мы поняли, что по стандарту числа должны храниться в формате double. Но это же плохо влияет на выделяемую память, её становится больше? Получается, если мы работаем с целыми числами, то у нас нет возможности обозначить, что число целое int и должно занимать в памяти 4 байта, а не 8! На самом деле, если взять к примеру наш любимый V8 и посмотреть в исходниках как создаётся примитивное значение Number:

Разные классы для чисел. Integer наследуется от NumberРазные классы для чисел. Integer наследуется от Number

То мы можем увидеть, что существует классы для создания разных типов чисел. И int и int32 и Uint32 (без знака ±), есть даже BigIntInteger наследуется от Number,  Int32 и Uint32 наследуются от Integer.

c9b2b1515532be3e2ec021d1a6cbe841.jpg

Файл можно посмотреть на gitHub’е:  https://github.com/v8/v8/blob/master/include/v8.h#L3039

То есть на самом деле V8 на C++ выделяет для переменной числа 4 байта если вы присвоите переменной целое число. Однако если вы динамически измените тип этой же переменной, то V8 придётся сделать тип этого числа уже double и выделить 8 байтов. Смена типов на лету является дорогой операцией, поэтому если вы заботитесь о производительности и быстродействии, то лучше так не делать и следить за этим.

Мы динамически изменили тип переменной для V8Мы динамически изменили тип переменной для V8

Изображение взято из статьи Performance Tip for JS in v8 Chris Wilsonhttps://www.html5rocks.com/en/tutorials/speed/v8/

Также хочу добавить одну интересную вещь. Чтобы вы не забывали JS — это одно, но мы в основном работаем с API браузера. Например, используем window.setTimeout(). Который не относится на прямую к JavaScript. Это относится к браузеру и setTimeout принимает в качестве аргумента число int32, которое как мы рассматривали в самом начале, может принимать максимальное целое число 2 147 483 647, но ни как не 9 квадрильонов. Если вы вызовите setTimout() с задержкой 2 147 483 648 (на 1 больше максимального значения Int32), то функция выполнится немедленно. Не путайте понятия JS и браузер. Нужно смотреть с какими числами работает каждый метод.

P.S. да, конечно никто не будет вызывать setTimeout в браузере на 25 дней. Но просто знание того, как это работает не помешает.

Всем спасибо, подписывайтесь на мою страничку в ВК и вступайте в нашу группу любителей frontend разработки

© Habrahabr.ru