Если вы изучали языки со строгой типизацией, то должны понимать,
что определённое значение должно храниться в памяти с заранее
выделенным для неё количеством байт. Например, для
числа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
.
Чтобы проверить, что числа действительно сравниваются не правильно, можно выполнить в консоли:
Сравнение чисел, которые больше максимально допустимого целого числа. Математически это не равные значения, однако нам вернётся true.Если вам нужно работать с большими числами и сравнивать их между
собой, то можно проверять является ли число безопасным с помощью
метода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 байтов. Смена типов на лету является дорогой операцией, поэтому если вы заботитесь о производительности и быстродействии, то лучше так не делать и следить за этим.
Мы динамически изменили тип переменной для V8Изображение взято из статьи Performance Tip for JS in v8Chris 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 разработки