BigInt
Значення BigInt
(велике ціле) представляють числові значення, котрі завеликі для представлення примітивом number
.
Опис
Значення BigInt, також іноді зване просто BigInt, є примітивом bigint
, створеним шляхом додавання в кінець літерала цілого числа n
, або ж викликом функції BigInt()
(без оператора new
) із передачею їй цілого числа або рядка.
const previouslyMaxSafeInteger = 9007199254740991n;
const alsoHuge = BigInt(9007199254740991);
// 9007199254740991n
const hugeString = BigInt("9007199254740991");
// 9007199254740991n
const hugeHex = BigInt("0x1fffffffffffff");
// 9007199254740991n
const hugeOctal = BigInt("0o377777777777777777");
// 9007199254740991n
const hugeBin = BigInt(
"0b11111111111111111111111111111111111111111111111111111",
);
// 9007199254740991n
Значення BigInt у певних аспектах подібні до значень Number, але також відрізняються в кількох ключових нюансах: значення BigInt не можуть використовуватися з методами вбудованого об'єкта Math
і не можуть змішуватися в операціях зі значеннями Number; усі значення повинні бути зведені до одного типу. Проте слід обережно зводити значення туди-назад, адже точність значення BigInt може бути втрачена при зведенні до значення Number.
Інформація про тип
При перевірці typeof
значення BigInt (примітив bigint
) дасть "bigint"
:
typeof 1n === "bigint"; // true
typeof BigInt("1") === "bigint"; // true
Значення BigInt також може бути загорнуто в Object
:
typeof Object(1n) === "object"; // true
Оператори
Більшість операторів підтримує BigInt, проте також більшість не дозволяє змішувати операнди різних типів – BigInt мають бути або обидва, або жоден:
- Арифметичні оператори:
+
,-
,*
,/
,%
,**
- Бітові оператори:
>>
,<<
,&
,|
,^
,~
- Унарне заперечення (
-
) - Збільшення та зменшення на одиницю:
++
,--
Оператори, що повертають булеві значення, дозволяють змішувати операнди-числа та BigInt:
- Оператори відношення та оператори рівності:
>
,<
,>=
,<=
,==
,!=
,===
,!==
- Логічні оператори покладаються лише на істинність операндів
Два оператори взагалі не підтримують BigInt:
- Унарний плюс (
+
) не може їх підтримувати у зв'язку з конфліктом використання в asm.js, тож його пропустили, щоб не ламати asm.js. - Беззнаковий зсув управо (
>>>
) – єдиний бітовий оператор, що не підтримує BigInt, адже кожне значення BigInt має знак.
Особливі випадки:
- Додавання (
+
) рядка та BigInt повертає рядок. - Ділення (
/
) відкидає дробові частини в бік до нуля, оскільки BigInt не може представляти дробові кількості.
const previousMaxSafe = BigInt(Number.MAX_SAFE_INTEGER); // 9007199254740991n
const maxPlusOne = previousMaxSafe + 1n; // 9007199254740992n
const theFuture = previousMaxSafe + 2n; // 9007199254740993n, тепер це працює!
const prod = previousMaxSafe * 2n; // 18014398509481982n
const diff = prod - 10n; // 18014398509481972n
const mod = prod % 10n; // 2n
const bigN = 2n ** 54n; // 18014398509481984n
bigN * -1n; // -18014398509481984n
const expected = 4n / 2n; // 2n
const truncated = 5n / 2n; // 2n, а не 2.5n
Порівняння
Значення BigInt строго не дорівнює значенню Number, проте дорівнює нестрого:
0n === 0; // false
0n == 0; // true
Значення Number і значення BigInt можуть порівнюватися як звично:
1n < 2; // true
2n > 1; // true
2 > 2; // false
2n > 2; // false
2n >= 2; // true
Значення BigInt і значення Number можуть змішуватися в масивах і сортуватися:
const mixed = [4n, 6, -12n, 10, 4, 0, 0n];
// [4n, 6, -12n, 10, 4, 0, 0n]
mixed.sort(); // усталена логіка сортування
// [ -12n, 0, 0n, 10, 4n, 4, 6 ]
mixed.sort((a, b) => a - b);
// не спрацює, адже віднімання не працює з різними типами
// TypeError: can't convert BigInt value to Number value
// сортування з адекватним числовим порівнювачем
mixed.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
// [ -12n, 0, 0n, 4n, 4, 6, 10 ]
Зверніть увагу, що порівняння загорнутих в Object
значень BigInt працює як для інших об'єктів – показує рівність лише тоді, коли порівнюється з собою один і той же примірник:
Object(0n) === 0n; // false
Object(0n) === Object(0n); // false
const o = Object(0n);
o === o; // true
Через те, що перетворення між значеннями Number та значеннями BigInt можуть призводити до втрати точності, рекомендовано наступне:
- Значення BigInt слід використовувати лише тоді, коли доцільно очікувати значень, більших за 253.
- Не слід перетворювати між собою значення BigInt і значення Number.
Перевірки умов
Значення BigInt відповідають тим самим правилам перетворення, що й Number, коли:
- перетворюються на
Boolean
– за допомогою функціїBoolean
; - використовуються з логічними операторами
||
,&&
і!
; або - зустрічаються в перевірках умов, як то інструкціях
if
.
А саме – лише 0n
є хибністю; все решта – істинність.
if (0n) {
console.log("Привіт з if!");
} else {
console.log("Привіт з else!");
}
// "Привіт з else!"
0n || 12n; // 12n
0n && 12n; // 0n
Boolean(0n); // false
Boolean(12n); // true
!12n; // false
!0n; // true
Криптографія
Операції, котрі підтримують значення BigInt, мають несталий час виконання, а тому вразливі до атак по часу. Таким чином, значення BigInt у JavaScript можуть бути небезпечними для використання в криптографії, якщо не вживати застережних заходів. Як дуже узагальнений приклад – нападник може виміряти часову різницю між 101n ** 65537n
і 17n ** 9999n
, завдяки чому – оцінити потужність таємних значень, як то приватних ключів, на основі витрат часу. Якщо все ж необхідно використовувати BigInt, слід звернутися до ЧаПів атак по часу щодо загальних порад на тему цієї проблеми.
Використання всередині JSON
Застосування JSON.stringify()
до будь-якого значення BigInt призведе до виринання TypeError
, адже значення BigInt усталено не серіалізуються в JSON. Проте JSON.stringify()
залишає саме для значень BigInt запасний хід: ця функція намагається викликати метод BigInt toJSON()
. (Вона не робить цього для будь-яких інших примітивних значень.) Таким чином, можна реалізувати власний метод toJSON()
(це один з тих небагатьох випадків, коли внесення змін до вбудованих об'єктів явно не знеохочується):
BigInt.prototype.toJSON = function () {
return { $bigint: this.toString() };
};
Замість викидання помилки, тепер JSON.stringify()
виробляє рядок:
console.log(JSON.stringify({ a: 1n }));
// {"a":{"$bigint":"1"}}
Коли не хочеться вносити зміни до BigInt.prototype
, можна застосувати для серіалізації значень BigInt параметр JSON.stringify
replacer
:
const replacer = (key, value) =>
typeof value === "bigint" ? { $bigint: value.toString() } : value;
const data = {
number: 1,
big: 18014398509481982n,
};
const stringified = JSON.stringify(data, replacer);
console.log(stringified);
// {"number":1,"big":{"$bigint":"18014398509481982"}}
Потім для обробки такого значення можна передати параметр reviver
методу JSON.parse
:
const reviver = (key, value) =>
value !== null &&
typeof value === "object" &&
"$bigint" in value &&
typeof value.$bigint === "string"
? BigInt(value.$bigint)
: value;
const payload = '{"number":1,"big":{"$bigint":"18014398509481982"}}';
const parsed = JSON.parse(payload, reviver);
console.log(parsed);
// { number: 1, big: 18014398509481982n }
[!NOTE] Хоч замінювач для
JSON.stringify()
можна зробити узагальненим, і коректно серіалізувати значення BigInt для всіх можливих об'єктів, як це показано вище, відновникаJSON.parse()
слід використовувати з обережністю, оскільки серіалізація є незворотною: неможливо відрізнити об'єкт, котрий, припустімо, просто має властивість з ім'ям$bigint
, від справжнього BigInt.Крім цього, приклад вище створює цілий об'єкт під час заміни та відновлення, що може мати вплив на продуктивність або використання пам'яті для більших об'єктів, що містять багато BigInt. Якщо форма корисного навантаження відома, може бути краще просто серіалізувати BigInt як рядки та відновлювати їх на основі імен властивостей.
Фактично JSON дозволяє числові літерали довільної довжини; їх просто не можна розібрати з повною точністю в JavaScript. Якщо відбувається комунікація з іншою програмою, написаною на мові, що підтримує довші цілі числа (наприклад, 64-бітові цілі), і необхідно передати BigInt як число JSON, а не рядок JSON, дивіться Серіалізацію чисел без втрат.
Зведення до BigInt
Чимало вбудованих операцій, котрі очікують на BigInt, спершу зводять свої аргументи до BigInt. Ця операція може бути підсумована отак:
- BigInt повертаються як є.
undefined
іnull
викидаютьTypeError
.true
стає1n
;false
стає0n
.- Рядки перетворюються шляхом розбору їх так, ніби вони містять цілочисловий літерал. Будь-яка невдача розбору призводить до
SyntaxError
. Синтаксис є підмножиною рядкових літералів чисел, у якій десятковий розділювач і експоненційний запис – заборонені. - Number викидають
TypeError
для запобігання небажаному неявному зведенню, що призвело б до втрати точності. - Symbol викидають
TypeError
. - Об'єкти спочатку перетворюються на примітиви шляхом виклику їх методів
[Symbol.toPrimitive]()
(з підказкою"number"
),valueOf()
іtoString()
– у такому порядку. Потім результівний примітив перетворюється на BigInt.
Найкращий спосіб досягнути в JavaScript майже такого ж ефекту – функція BigInt()
: BigInt(x)
використовує такий же алгоритм для перетворення x
, окрім того, що Number не викидають TypeError
, а перетворюються на BigInt, якщо є цілими числами.
Зверніть увагу, що вбудовані операції, котрі очікують на BigInt, нерідко після зведення обрізають BigInt до фіксованої ширини. Серед таких операцій – BigInt.asIntN()
, BigInt.asUintN()
, а також методи об'єктів BigInt64Array
і BigUint64Array
.
Конструктор
BigInt()
Повертає примітивні значення типу BigInt. Викидає помилку, коли викликати його з
new
.
Статичні методи
BigInt.asIntN()
Обрізає значення BigInt до знакового цілого числа, і повертає його.
BigInt.asUintN()
Обрізає значення BigInt до беззнакового цілого числа, і повертає його.
Властивості примірника
Ці властивості означені на BigInt.prototype
і є спільними для всіх примірників BigInt
.
BigInt.prototype.constructor
Функція-конструктор, що створила об'єкт-примірник. Для примірників
BigInt
початкове значення – конструкторBigInt
.BigInt.prototype[Symbol.toStringTag]
Початкове значення
[Symbol.toStringTag]
– рядок"BigInt"
. Ця властивість використовується вObject.prototype.toString()
. Проте у зв'язку з тим, щоBigInt
також має власну реалізацію методаtoString()
, ця властивість не використовується, якщо не викликатиObject.prototype.toString.call()
зі значенням BigInt якthisArg
.
Методи примірника
BigInt.prototype.toLocaleString()
Повертає рядок з чутливим до мови представленням цього значення BigInt. Заміщає метод
Object.prototype.toLocaleString()
.BigInt.prototype.toString()
Повертає рядкове представлення цього значення BigInt за заданою основою числення. Заміщає метод
Object.prototype.toString()
.BigInt.prototype.valueOf()
Повертає поточне значення BigInt. Заміщає метод
Object.prototype.valueOf()
.
Приклади
Обчислення простих чисел
// Повертає true, якщо передане значення BigInt є простим числом
function isPrime(p) {
for (let i = 2n; i * i <= p; i++) {
if (p % i === 0n) return false;
}
return true;
}
// Приймає за аргумент значення BigInt, повертає n-не просте число у вигляді значення BigInt
function nthPrime(nth) {
let maybePrime = 2n;
let prime = 0n;
while (nth >= 0n) {
if (isPrime(maybePrime)) {
nth--;
prime = maybePrime;
}
maybePrime++;
}
return prime;
}
nthPrime(20n);
// 73n
Специфікації
Сумісність із браузерами
desktop | mobile | server | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
BigInt
|
Chrome Full support 67 | Edge Full support 79 | Firefox Full support 68 | Internet Explorer No support Ні | Opera Full support 54 | Safari Full support 14 | WebView Android Full support 67 | Chrome Android Full support 67 | Firefox for Android Full support 68 | Opera Android Full support 48 | Safari on iOS Full support 14 | Samsung Internet Full support 9.0 | Deno Full support 1.0 | Node.js Full support 10.4.0 |
BigInt() constructor
|
Chrome Full support 67 | Edge Full support 79 | Firefox Full support 68 | Internet Explorer No support Ні | Opera Full support 54 | Safari Full support 14 | WebView Android Full support 67 | Chrome Android Full support 67 | Firefox for Android Full support 68 | Opera Android Full support 48 | Safari on iOS Full support 14 | Samsung Internet Full support 9.0 | Deno Full support 1.0 | Node.js Full support 10.4.0 |
asIntN
|
Chrome Full support 67 | Edge Full support 79 | Firefox Full support 68 | Internet Explorer No support Ні | Opera Full support 54 | Safari Full support 14 | WebView Android Full support 67 | Chrome Android Full support 67 | Firefox for Android Full support 68 | Opera Android Full support 48 | Safari on iOS Full support 14 | Samsung Internet Full support 9.0 | Deno Full support 1.0 | Node.js Full support 10.4.0 |
asUintN
|
Chrome Full support 67 | Edge Full support 79 | Firefox Full support 68 | Internet Explorer No support Ні | Opera Full support 54 | Safari Full support 14 | WebView Android Full support 67 | Chrome Android Full support 67 | Firefox for Android Full support 68 | Opera Android Full support 48 | Safari on iOS Full support 14 | Samsung Internet Full support 9.0 | Deno Full support 1.0 | Node.js Full support 10.4.0 |
toLocaleString
|
Chrome Full support 67 | Edge Full support 79 | Firefox Full support 68 | Internet Explorer No support Ні | Opera Full support 54 | Safari Full support 14 | WebView Android Full support 67 | Chrome Android Full support 67 | Firefox for Android Full support 68 | Opera Android Full support 48 | Safari on iOS Full support 14 | Samsung Internet Full support 9.0 | Deno Full support 1.0 | Node.js Full support 10.4.0 |
toLocaleString.locales
|
Chrome Full support 76 | Edge Full support 79 | Firefox Full support 70 | Internet Explorer No support Ні | Opera No support Ні | Safari Full support 14 | WebView Android Full support 76 | Chrome Android Full support 76 | Firefox for Android Full support 79 | Opera Android Full support 54 | Safari on iOS Full support 14 | Samsung Internet Full support 12.0 | Deno Full support 1.8 | Node.js Full support 12.9.0 |
toLocaleString.options
|
Chrome Full support 76 | Edge Full support 79 | Firefox Full support 70 | Internet Explorer No support Ні | Opera No support Ні | Safari Full support 14 | WebView Android Full support 76 | Chrome Android Full support 76 | Firefox for Android Full support 79 | Opera Android Full support 54 | Safari on iOS Full support 14 | Samsung Internet Full support 12.0 | Deno Full support ?null | Node.js Full support 12.9.0 |
toString
|
Chrome Full support 67 | Edge Full support 79 | Firefox Full support 68 | Internet Explorer No support Ні | Opera Full support 54 | Safari Full support 14 | WebView Android Full support 67 | Chrome Android Full support 67 | Firefox for Android Full support 68 | Opera Android Full support 48 | Safari on iOS Full support 14 | Samsung Internet Full support 9.0 | Deno Full support 1.0 | Node.js Full support 10.4.0 |
valueOf
|
Chrome Full support 67 | Edge Full support 79 | Firefox Full support 68 | Internet Explorer No support Ні | Opera Full support 54 | Safari Full support 14 | WebView Android Full support 67 | Chrome Android Full support 67 | Firefox for Android Full support 68 | Opera Android Full support 48 | Safari on iOS Full support 14 | Samsung Internet Full support 9.0 | Deno Full support 1.0 | Node.js Full support 10.4.0 |