Пошук уроків, статей та іншого контенту
Дізнайтеся, навіщо потрібен BigInt і як працювати з цілими числами, що перевищують безпечний діапазон типу number. Розгляньте обмеження та особливості операцій із BigInt.
bigintТип number у JavaScript використовує формат IEEE 754 із подвійною точністю. Він може точно представляти цілі числа лише в діапазоні:
Number.MIN_SAFE_INTEGER; // -9007199254740991
Number.MAX_SAFE_INTEGER; // 9007199254740991Цей діапазон називають безпечним, тому що всі цілі числа в ньому можна точно зберегти та порівняти.
За межами діапазону можуть виникати помилки точності:
const first = Number.MAX_SAFE_INTEGER + 1;
const second = Number.MAX_SAFE_INTEGER + 2;
console.log(first); // 9007199254740992
console.log(second); // 9007199254740992
console.log(first === second); // trueФактично ми додали до числа різні значення, але отримали однаковий результат.
bigint призначений для роботи з цілими числами довільної точності. Він дає змогу зберігати значення, більші за Number.MAX_SAFE_INTEGER, без втрати точності.
bigintНайпростіший спосіб — додати суфікс n до цілого числового літерала:
const usersCount = 9007199254740993n;
const negativeValue = -42n;
const zero = 0n;
console.log(usersCount);
console.log(typeof usersCount); // bigintТакож значення можна створити за допомогою функції BigInt:
const valueFromString = BigInt("900719925474099312345");
const valueFromNumber = BigInt(42);
console.log(valueFromString);
console.log(valueFromNumber);Рекомендується передавати в BigInt рядок, якщо число вже не поміщається в безпечний діапазон number:
const correct = BigInt("9007199254740993");
// Це число вже було неточно представлене як number
const incorrect = BigInt(9007199254740993);
console.log(correct); // 9007199254740993n
console.log(incorrect); // 9007199254740992nПеретворення рядка працює для цілих чисел:
BigInt("123"); // 123n
BigInt("-45"); // -45n
BigInt("0x10"); // 16n
BigInt("0b1010"); // 10nДробові значення перетворити на bigint не можна:
// BigInt("10.5"); // TypeError
// BigInt(10.5); // RangeErrorДля значень bigint доступні основні арифметичні операції:
const a = 9007199254740993n;
const b = 7n;
console.log(a + b); // 9007199254741000n
console.log(a - b); // 9007199254740986n
console.log(a * b); // 63050394783222951n
console.log(a ** 2n);
console.log(a % b);Результатом операції над bigint також є bigint.
Ділення bigint відкидає дробову частину, оскільки bigint зберігає лише цілі числа:
console.log(10n / 3n); // 3n
console.log(-10n / 3n); // -3n
console.log(10n % 3n); // 1nДілення на нуль спричиняє помилку:
// console.log(10n / 0n); // RangeError: Division by zeroОператори ++ і -- працюють із bigint:
let counter = 10n;
counter++;
console.log(counter); // 11n
counter--;
console.log(counter); // 10nnumber і bigintJavaScript не виконує автоматичне змішування number і bigint у більшості арифметичних операцій:
const bigValue = 10n;
const regularValue = 5;
// bigValue + regularValue; // TypeErrorПотрібно явно привести значення до одного типу:
const bigValue = 10n;
const regularValue = 5;
console.log(bigValue + BigInt(regularValue)); // 15n
console.log(Number(bigValue) + regularValue); // 15Перетворення великого bigint на number може призвести до втрати точності:
const value = 9007199254740993n;
const converted = Number(value);
console.log(converted); // 9007199254740992Тому перетворюйте bigint на number лише тоді, коли впевнені, що значення входить у безпечний діапазон.
Оператори порівняння можуть працювати з number і bigint разом:
console.log(10n == 10); // true
console.log(10n === 10); // false
console.log(5n < 10); // true
console.log(10n >= 10); // trueНестроге порівняння == порівнює значення після приведення типів, а строге === перевіряє і значення, і тип.
Для передбачуваної поведінки зазвичай краще не змішувати типи або явно приводити їх до одного типу.
const first = 100n;
const second = BigInt(100);
console.log(first === second); // trueЛогічні оператори також можуть використовувати bigint як умовне значення:
console.log(Boolean(0n)); // false
console.log(Boolean(1n)); // true
console.log(Boolean(42n)); // trueДля bigint доступні побітові операції:
const left = 0b1100n;
const right = 0b1010n;
console.log(left & right); // 8n
console.log(left | right); // 14n
console.log(left ^ right); // 6n
console.log(left << 1n); // 24n
console.log(left >> 1n); // 6n
console.log(~left); // -13nОператор беззнакового зсуву вправо >>> для bigint не підтримується. Для знакових значень використовуйте >>.
bigint не є повною заміною number. Зокрема:
не можна використовувати унарний плюс +value;
не можна безпосередньо передавати в методи об’єкта Math;
значення не можуть містити дробову частину;
не можна змішувати number і bigint в арифметичних виразах.
const value = 10n;
// console.log(+value); // TypeError
// console.log(Math.abs(value)); // TypeErrorДля обчислень із дробовими значеннями використовуйте number або спеціалізовані бібліотеки для десяткової арифметики.
Уявімо, що потрібно обчислити кількість мілісекунд у дуже великому проміжку часу. Значення може перевищити безпечний діапазон number.
const days = 100_000_000n;
const hoursInDay = 24n;
const minutesInHour = 60n;
const secondsInMinute = 60n;
const millisecondsInSecond = 1000n;
const milliseconds =
days *
hoursInDay *
minutesInHour *
secondsInMinute *
millisecondsInSecond;
console.log(milliseconds);
console.log(typeof milliseconds); // bigintУсі проміжні результати залишаються точними, оскільки операції виконуються над значеннями bigint.
bigint можна перетворити на рядок за допомогою String або методу toString:
const value = 12345678901234567890n;
console.log(String(value)); // "12345678901234567890"
console.log(value.toString()); // "12345678901234567890"
console.log(value.toString(16)); // шістнадцяткове представлення
console.log(value.toString(2)); // двійкове представленняЦе корисно для виведення значень, обміну даними або збереження їх у текстовому форматі.
bigint і JSONСтандартний JSON.stringify не вміє автоматично серіалізувати bigint:
const data = {
id: 12345678901234567890n,
};
// JSON.stringify(data); // TypeErrorПеред серіалізацією значення потрібно перетворити на рядок:
const data = {
id: 12345678901234567890n,
name: "Order",
};
const json = JSON.stringify(data, (_, value) => {
// Великі цілі числа зберігаємо як рядки
return typeof value === "bigint" ? value.toString() : value;
});
console.log(json);Після JSON.parse таке поле буде рядком. Якщо потрібно повернути його до bigint, це треба зробити явно:
const parsed = JSON.parse(json);
const orderId = BigInt(parsed.id);
console.log(orderId);На практиці ідентифікатори та великі числові значення часто передають через API саме як рядки, щоб не втратити точність у різних мовах і середовищах.
bigint у масивах і сортуванніМасив може містити значення bigint:
const values = [30n, 5n, 100n, 20n];
values.sort((a, b) => {
if (a < b) return -1;
if (a > b) return 1;
return 0;
});
console.log(values); // [5n, 20n, 30n, 100n]Не варто використовувати вираз Number(a - b) у функції сортування для дуже великих значень, якщо результат може втратити точність.
bigintbigint доречний, коли:
потрібно працювати з цілими числами понад Number.MAX_SAFE_INTEGER;
важлива точність кожної цифри;
обчислюються великі лічильники, фінансові або технічні ідентифікатори;
реалізуються алгоритми з великими цілими числами;
дані надходять із систем, де цілі числа можуть бути довільного розміру.
bigint не потрібен для більшості звичайних лічильників, індексів масивів і побутових обчислень. У таких випадках достатньо number.
n до дробового числа// const value = 10.5n; // SyntaxErrorbigint підтримує лише цілі числа.
const count = 10n;
const increment = 1;
// count + increment; // TypeErrorПотрібно явно привести одне зі значень:
console.log(count + BigInt(increment)); // 11nnumberconst value = BigInt(9007199254740993);
console.log(value); // 9007199254740992nЧисло вже втратило точність до виклику BigInt. Використовуйте рядок:
const value = BigInt("9007199254740993");
console.log(value); // 9007199254740993nconsole.log(5n / 2n); // 2nЯкщо потрібен дробовий результат, потрібно явно перетворити значення на number, розуміючи можливу втрату точності:
console.log(Number(5n) / Number(2n)); // 2.5bigint у JSON.stringify// JSON.stringify({ value: 1n }); // TypeErrorПеретворюйте bigint на рядок або використовуйте власний серіалізатор.
bigint призначений для точних обчислень із великими цілими числами.
Значення можна записувати із суфіксом n: 123n.
Функція BigInt створює значення з рядка або безпечного цілого number.
number і bigint не можна змішувати в арифметичних операціях.
Ділення bigint відкидає дробову частину.
Перетворення великого bigint на number може призвести до втрати точності.
bigint не підтримує дробові значення та більшість методів Math.
JSON.stringify не серіалізує bigint автоматично, тому зазвичай його перетворюють на рядок.