Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Если вы изучали языки со строгой типизацией, то должны понимать, что определённое значение должно храниться в памяти с заранее выделенным для неё количеством байт. Например, для числа 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 — мантисса, всё что идёт после запятой).
Диапазон значений: 1,7E +/- 308 (15 знаков). Вы можете проверить и посмотреть это число полностью, выведя в консоли максимальное допустимое число объекта Number: Number.MAX_VALUE
.Вот ссылка на стандарт IEEE754: https://en.wikipedia.org/wiki/IEEE_754Если выйти за пределы этого числа, то Number выдаст нам значение Infinity
.
Хорошо, но сколько же целых чисел можно выразить с помощью double
?
Ответ: 9,007,199,254,740,991 или~9 квадрильонов. Все числа до этого числа являются безопасными, что значит их можно сравнивать между собой. Данное максимально безопасное число также можно получить используя объект Number: Number.MAX_SAFE_INTEGER
.
Чтобы проверить, что числа действительно сравниваются не правильно, можно выполнить в консоли:
Если вам нужно работать с большими числами и сравнивать их между собой, то можно проверять является ли число безопасным с помощью метода isSafeInteger()
:
Хорошо, мы поняли, что по стандарту числа должны храниться в формате double
. Но это же плохо влияет на выделяемую память, её становится больше? Получается, если мы работаем с целыми числами, то у нас нет возможности обозначить, что число целое int
и должно занимать в памяти 4 байта, а не 8! На самом деле, если взять к примеру наш любимый V8 и посмотреть в исходниках как создаётся примитивное значение Number:
То мы можем увидеть, что существует классы для создания разных типов чисел. И int
и int32
и Uint32
(без знака ±), есть даже BigInt
. Integer
наследуется от Number
, Int32
и Uint32
наследуются от Integer
.
Файл можно посмотреть на gitHub'е: https://github.com/v8/v8/blob/master/include/v8.h#L3039
То есть на самом деле V8 на C++ выделяет для переменной числа 4 байта если вы присвоите переменной целое число. Однако если вы динамически измените тип этой же переменной, то V8 придётся сделать тип этого числа уже double и выделить 8 байтов. Смена типов на лету является дорогой операцией, поэтому если вы заботитесь о производительности и быстродействии, то лучше так не делать и следить за этим.
Изображение взято из статьи 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 разработки