Основным числовым типом в JavaScript является тип Number
, используемый для представления целых чисел и приближенных действительных чисел. JavaScript использует 64-битный формат с плавающей запятой, определенный стандартом IEEE 754, для представления числовых значений. Это означает, что JavaScript может представлять максимальное целое число ±1,797 693 134 862 315 7 × 10^308 и минимальное целое число ±5 × 10^-324.
Этот числовой формат в JavaScript позволяет нам точно представлять все целые числа от -9 007 199 254 740 992 (-2⁵³) до 9 007 199 254 740 992 (2⁵³) включительно. Если ваше значение выходит за пределы этого диапазона, вы можете столкнуться с некоторой потерей точности младших цифр.
Когда числовое значение появляется непосредственно в программе JavaScript, оно называется «числовым литералом». Обратите внимание, что любой числовой литерал может иметь префикс со знаком минус (-), чтобы сделать значение отрицательным.
1.Целочисленные литералы.
В программах JavaScript десятичные целые числа с основанием 10 можно записать непосредственно в виде последовательности цифр. Например:
0 3 10000000
Помимо десятичных целочисленных литералов, JavaScript также поддерживает шестнадцатеричные значения (по основанию 16). Шестнадцатеричные литералы начинаются с 0x
или 0X
, за которыми следует строка шестнадцатеричных цифр. Шестнадцатеричные цифры состоят из цифр от 0 до 9 и букв от a (или A) до f (или F), где от a до f представляют числа от 10 до 15. Вот примеры шестнадцатеричных целочисленных литералов:
//=> 255: (15*16 + 15) 0xff //=> 195939070 0xBADCAFE
В ES6 и более поздних версиях вы также можете представлять целые числа в двоичном (основание 2) или восьмеричном (основание 8) с помощью префиксов 0b
и 0o
(или 0B
и 0O
):
//=> 21: (1*16 + 0*8 + 1*4 + 0*2 + 1*1) 0b10101 //=> 255: (3*64 + 7*8 + 7*1) 0o377
(Мягкие навыки для программистов: amazon.com/dp/B0CF599P8J)
2. Литералы с плавающей запятой.
Литералы с плавающей запятой могут включать десятичную точку и следовать традиционному синтаксису действительных чисел. Действительное значение состоит из целой части числа, десятичной точки и дробной части числа.
Литералы с плавающей запятой также могут использовать экспоненциальную запись, где за действительным значением следует буква e
(или E
), необязательный знак плюс или минус и целочисленный показатель степени. Это обозначение представляет собой реальное значение, умноженное на 10, возведенное в степень экспоненты.
Более краткая форма синтаксиса:
[digits][.digits][(E|e)[(+|-)]digits]
Например:
3.14 2345.6789 .333333333333333333 //6.02 x 10^23 6.02e23 //1.4738223 x 10^-32 1.4738223E-32
Вы можете использовать символы подчеркивания для разделения разделов числовых литералов. Эта функция перешла на более поздние стадии стандартизации и поддерживается всеми основными браузерами и реализациями Node:
// Using underscores as a thousands separator let billion = 1_000_000_000; // Using underscores as a byte separator let bytes = 0x89_AB_CD_EF; // Using underscores as a nibble separator let bits = 0b0001_1101_0111; // Can also be used in the fractional part let fraction = 0.123_456_789;
(Мягкие навыки для программистов: amazon.com/dp/B0CF599P8J)
3. Арифметика в JavaScript.
Программы JavaScript используют арифметические операторы, предоставляемые языком, для управления числовыми значениями. К этим операторам относятся сложение +
, вычитание -
, умножение *
, деление /
и по модулю (остаток после деления) %
. В ES2016 появился оператор возведения в степень **
.
В дополнение к этим основным арифметическим операторам JavaScript также предоставляет набор функций и констант через объект Math
для поддержки более сложных математических вычислений:
// => 9007199254740992: 2 raised to the power of 53 Math.pow(2, 53) // => 1.0: rounded to the nearest integer Math.round(0.6) // => 1.0: rounded up to the nearest integer Math.ceil(0.6) // => 0.0: rounded down to the nearest integer Math.floor(0.6) // => 5: absolute value Math.abs(-5) // returns the maximum of the provided arguments Math.max(x, y, z) // returns the minimum of the provided arguments Math.min(x, y, z) // pseudo-random number x, where 0 <= x < 1.0 Math.random() // π: constant representing the mathematical constant pi Math.PI // e: constant representing the base of the natural logarithm Math.E // => 3**0.5: square root of 3 Math.sqrt(3) // => 3**(1/3): cube root of 3 Math.pow(3, 1/3) // trigonometric functions: also Math.cos, Math.atan, etc. Math.sin(0) // natural logarithm of 10 Math.log(10) // logarithm base 10 of 100 Math.log(100) / Math.LN10 // logarithm base 2 of 512 Math.log(512) / Math.LN2 // cube of Math.E Math.exp(3)
ES6 представил новый набор функций для объекта Math
:
// => 3: cube root Math.cbrt(27) // => 5: square root of the sum of squares of all arguments Math.hypot(3, 4) // => 2: base 10 logarithm Math.log10(100) // => 10: base 2 logarithm Math.log2(1024) // natural logarithm of (1+x): precise for very small x Math.log1p(x) // Math.exp(x) - 1; inverse of Math.log1p() Math.expm1(x) // returns -1, 0, or 1 depending on the sign of the argument Math.sign(x) // => 6: optimized 32-bit integer multiplication Math.imul(2, 3) // => 28: number of leading zero bits in the 32-bit binary representation Math.clz32(0xf) // => 3: removes the fractional part to get an integer Math.trunc(3.9) // rounds to the nearest 32-bit floating point value Math.fround(x) // hyperbolic sine, also Math.cosh() and Math.tanh() Math.sinh(x) // hyperbolic arcsine, also Math.acosh() and Math.atanh() Math.asinh(x)
Арифметика в JavaScript не выдает ошибок при переполнении, опустошении или делении на ноль. Когда результат числовой операции превышает представимый диапазон (переполнение), результатом является специальное бесконечное значение Infinity
. Аналогично, когда абсолютное значение отрицательного числа превышает представимый диапазон отрицательных чисел (недополнение), результатом будет отрицательная бесконечность -Infinity
. Поведение этих двух бесконечных значений соответствует ожиданиям: любая арифметическая операция, включающая сложение, вычитание, умножение или деление с бесконечностью, приводит к бесконечности (хотя знак может измениться).
Недополнение происходит, когда результат числовой операции приближается к нулю, но все еще больше наименьшего представимого числа. В этом случае JavaScript возвращает 0. Если в случае обратного значения происходит нижнее переполнение, JavaScript возвращает специальное значение, известное как «отрицательный ноль». Это значение почти неотличимо от обычного нуля и редко вызывает беспокойство у программистов JavaScript.
Деление на ноль не является ошибкой в JavaScript; это просто приводит к бесконечности или отрицательной бесконечности. Однако есть исключение: при делении 0 на 0 получается особое значение, называемое «Не число» (NaN
). Кроме того, такие операции, как деление бесконечности на бесконечность, квадратный корень из отрицательного числа или использование NaN в качестве операнда в арифметических операциях, в результате дают NaN
.
JavaScript предопределяет глобальные константы Infinity
и NaN
так, чтобы они соответствовали положительной бесконечности и не числу соответственно. Доступ к этим значениям также можно получить через свойства объекта Number
:
// Positive infinity due to being too large to represent Infinity // Same as above Number.POSITIVE_INFINITY // => Infinity 1 / 0 // => Infinity; overflow Number.MAX_VALUE * 2 // Negative infinity due to being too large to represent as a negative number -Infinity // Same as above Number.NEGATIVE_INFINITY // => -Infinity -1 / 0 // => -Infinity -Number.MAX_VALUE * 2 // NaN: Not a Number NaN // Same as above, different syntax Number.NaN // => NaN 0 / 0 // => NaN Infinity / Infinity // => 0: underflow Number.MIN_VALUE / 2 // => -0: negative zero -Number.MIN_VALUE / 2 // => -0: also negative zero -1 / Infinity // -0
ES6 представил следующие свойства объекта Number
:
// Same as global parseInt() function Number.parseInt() // Same as global parseFloat() function Number.parseFloat() // Check if x is NaN Number.isNaN(x) // Check if x is a finite number Number.isFinite(x) // Check if x is an integer Number.isInteger(x) // Number.isSafeInteger(x) // => -(2**53 - 1) Number.MIN_SAFE_INTEGER // => 2**53 - 1 Number.MAX_SAFE_INTEGER // => 2**-52: smallest difference between two representable numbers Number.EPSILON
NaN имеет необычную характеристику в JavaScript: он не равен и не равен никакому значению, включая самого себя. Это означает, что вы не можете определить, является ли переменная x
значением NaN, используя сравнение x === NaN
. Вместо этого вы должны использовать x != x
или Number.isNaN(x)
для проверки NaN. Оба этих выражения возвращают true
только в том случае, если x
имеет то же значение, что и глобальная константа NaN
.
Глобальная функция isNaN()
аналогична Number.isNaN()
. Он возвращает true
, если аргумент имеет значение NaN или когда аргумент представляет собой нечисловое значение, которое невозможно преобразовать в число. Связанная функция Number.isFinite()
возвращает true
, если аргумент не равен NaN, Infinity или -Infinity. Глобальная функция isFinite()
возвращает true
, если аргумент представляет собой конечное число или значение, которое можно преобразовать в конечное число.
Отрицательный ноль ведет себя несколько необычно. Он считается равным положительному нулю (даже при использовании строгого сравнения на равенство в JavaScript), а это означает, что, помимо его роли делителя, сложно различить эти два значения:
// Regular zero let zero = 0; // Negative zero let negz = -0; // => true: zero equals negative zero zero === negz // => false: Infinity does not equal negative infinity 1 / zero === 1 / negz
(Мягкие навыки для программистов: amazon.com/dp/B0CF599P8J)
4. Двоичные числа с плавающей запятой и ошибки округления.
Действительных чисел бесконечно много, но формат с плавающей запятой в JavaScript может представлять только их конечное подмножество (точнее, он может представлять до 18 437 736 874 454 810 627 различных значений). Это означает, что когда вы работаете с действительными числами в JavaScript, числовые значения, которыми вы манипулируете, часто приближаются к фактическим значениям.
JavaScript (как и все современные языки программирования) использует представление с плавающей запятой IEEE-754, которое является двоичным представлением. Это представление может точно представлять такие дроби, как 1/2, 1/8 и 1/1024. Однако наиболее распространенными дробями, которые мы используем (особенно в финансовых расчетах), являются десятичные дроби, такие как 1/10, 1/100 и так далее. Двоичное представление с плавающей запятой не может точно представлять даже простые числа, такие как 0,1.
Хотя числовые значения JavaScript имеют достаточную точность, чтобы очень близко приближаться к 0,1, они не могут точно ее представить. Это может привести к проблемам, как показано в следующем коде:
// 30 cents minus 20 cents let x = 0.3 - 0.2; // 20 cents minus 10 cents let y = 0.2 - 0.1; // => false: These two values are not equal! x === y // => false: .3 - .2 is not equal to .1 x === 0.1 // => true: .2 - .1 is equal to .1 y === 0.1
Из-за ошибок округления разница между приблизительными значениями 0,3 и 0,2 не равна разнице между приблизительными значениями 0,2 и 0,1. Это не проблема, специфичная для JavaScript; это общая проблема всех языков программирования, использующих двоичные числа с плавающей запятой. Также важно отметить, что значения x
и y
в приведенном выше коде очень близки и очень близки к правильным значениям. Рассчитанные значения идеально подходят для большинства целей, но пытаться сравнить их на предмет точного равенства не рекомендуется.
Если приблизительные значения с плавающей запятой создают проблемы в вашей программе, вы можете рассмотреть возможность использования эквивалентных целых чисел. Например, при расчетах, связанных с деньгами, вы можете работать с целочисленными представлениями центов, а не с долями доллара.
(Мягкие навыки для программистов: amazon.com/dp/B0CF599P8J)
5. Представление целых чисел произвольной точности с помощью Bigint.
В ES2020 в JavaScript появился новый числовой тип BigInt. По состоянию на начало 2020 года этот тип реализован в Chrome, Firefox, Edge и Node.js, над ним также работает Safari. Как следует из названия, значения BigInt являются целыми числами. Основной мотивацией для добавления этого типа было представление 64-битных целых чисел, что имеет решающее значение для совместимости со многими другими языками и API. Однако значения BigInt могут состоять из тысяч или даже миллионов цифр, что удовлетворяет потребности в больших числах (хотя реализации BigInt не подходят для шифрования, поскольку не учитывают защиту от атак по времени).
Литералы BigInt записываются как последовательность цифр, за которой следует строчная буква «n». По умолчанию система счисления равна 10, но вы можете представлять двоичные, восьмеричные и шестнадцатеричные числа BigInt, используя префиксы 0b, 0o и 0x соответственно:
// A not-so-large BigInt literal 1234n // Binary BigInt 0b111111n // Octal BigInt 0o7777n // => 2n ** 63n: A 64-bit integer 0x8000000000000000n
Вы можете преобразовать обычные числа или строки JavaScript в значения BigInt с помощью функции BigInt():
// => 9007199254740991n BigInt(Number.MAX_SAFE_INTEGER) // A 1 followed by 100 zeros let string = "1" + "0".repeat(100); // => 10n ** 100n: An astronomical number BigInt(string)
Арифметические операции со значениями BigInt аналогичны обычным числовым операциям JavaScript, за исключением того, что при делении остаток отбрасывается и округляется в сторону нуля:
// => 3000n 1000n + 2000n // => 1000n 3000n - 2000n // => 6000000n 2000n * 3000n // => 3n: Quotient is 3 3000n / 997n // => 9n: Remainder is 9 3000n % 997n // A Mersenne prime with 39457 digits (2n ** 131071n) - 1n
Хотя стандартные операторы +, -, *, /, % и ** работают с BigInt, вы не можете смешивать операнды BigInt с обычными числовыми операндами. Это правило может показаться странным на первый взгляд, но на самом деле оно разумно. Если один числовой тип является более общим, чем другой, можно легко определить вычисления со смешанными операндами и вернуть более общий тип. Однако в данном случае ни один из двух типов не является более общим, чем другой: BigInt может представлять очень большие значения, что делает его более общим, чем обычные числовые типы. Но BigInt может представлять только целые числа, что делает обычные числовые типы JavaScript более общими в этом аспекте. Эту дилемму решить невозможно, поэтому JavaScript просто запрещает смешивать эти два типа операндов при использовании арифметических операторов.
С другой стороны, операторы сравнения позволяют смешивать типы операндов:
// => true 1 < 2n // => true 2 > 1n // => true 0 == 0n // => false: === also checks for type equality 0 == 0n
Побитовые операторы обычно можно использовать с операндами BigInt. Однако ни одна из функций объекта Math не принимает операнды BigInt.
(Мягкие навыки для программистов: amazon.com/dp/B0CF599P8J)
6. Даты и время.
JavaScript предоставляет простой класс Date для представления и управления данными, связанными с датами и временем. Дата в JavaScript — это объект, но он также имеет числовое представление, известное как временная метка, которая представляет собой количество миллисекунд, прошедших с 1 января 1970 года:
// Timestamp (numeric) of the current time let timestamp = Date.now(); // Date object of the current time let now = new Date(); // Convert to milliseconds timestamp let ms = now.getTime(); // Convert to a string in ISO format let iso = now.toISOString();
(Мягкие навыки для программистов: amazon.com/dp/B0CF599P8J)