Изчерпателно ръководство за типа BigInt в JavaScript, обхващащо неговите характеристики, употреба и приложения при работа с големи цели числа. Научете как да преодолеете ограниченията на JavaScript и да извършвате сложни изчисления с точност.
JavaScript BigInt: Овладяване на аритметика с големи цели числа
JavaScript, макар и универсален език, има ограничения при работа с много големи цели числа. Стандартният тип `Number` може точно да представя цели числа само до определена граница, известна като `Number.MAX_SAFE_INTEGER`. Отвъд тази граница изчисленията стават неточни, което води до неочаквани резултати. Тук на помощ идва BigInt
. Въведен в ECMAScript 2020, BigInt
е вграден обект, който предоставя начин за представяне и манипулиране на цели числа с произволен размер, надхвърляйки ограниченията на стандартния тип `Number`.
Разбиране на нуждата от BigInt
Преди BigInt
, разработчиците на JavaScript трябваше да разчитат на библиотеки или персонализирани имплементации за обработка на изчисления с големи цели числа. Тези решения често водеха до намалена производителност и повишена сложност. Въвеждането на BigInt
предостави вграден и ефективен начин за работа с големи цели числа, отваряйки възможности за приложения в различни области, включително:
- Криптография: Сигурната обработка на големи прости числа е от решаващо значение за криптографските алгоритми.
- Финансови изчисления: Точно представяне на големи парични стойности без загуба на прецизност.
- Научни изчисления: Извършване на сложни изчисления, включващи изключително големи или малки числа.
- Времеви маркери с висока прецизност: Представяне на времеви маркери с наносекундна точност.
- Генериране на ID: Създаване на уникални и много големи идентификатори.
Създаване на BigInt стойности
Има два основни начина за създаване на BigInt
стойности в JavaScript:
- Използване на конструктора `BigInt()`: Този конструктор може да преобразува число, низ или булева стойност в
BigInt
. - Използване на суфикса `n`: Добавянето на `n` към цяло число създава
BigInt
.
Примери:
Използване на конструктора `BigInt()`:
const bigIntFromNumber = BigInt(12345678901234567890);
const bigIntFromString = BigInt("98765432109876543210");
const bigIntFromBoolean = BigInt(true); // Резултатът е 1n
const bigIntFromFalseBoolean = BigInt(false); // Резултатът е 0n
console.log(bigIntFromNumber); // Изход: 12345678901234567890n
console.log(bigIntFromString); // Изход: 98765432109876543210n
console.log(bigIntFromBoolean); // Изход: 1n
console.log(bigIntFromFalseBoolean); // Изход: 0n
Използване на суфикса `n`:
const bigIntLiteral = 12345678901234567890n;
console.log(bigIntLiteral); // Изход: 12345678901234567890n
Важна забележка: Не можете директно да смесвате BigInt
и Number
стойности в аритметични операции. Трябва изрично да ги преобразувате в един и същ тип, преди да извършвате изчисления. Опитът за директното им смесване ще доведе до `TypeError`.
Аритметични операции с BigInt
BigInt
поддържа повечето от стандартните аритметични оператори, включително:
- Събиране (`+`)
- Изваждане (`-`)
- Умножение (`*`)
- Деление (`/`)
- Остатък (`%`)
- Степенуване (`**`)
Примери:
const a = 12345678901234567890n;
const b = 98765432109876543210n;
const sum = a + b;
const difference = a - b;
const product = a * b;
const quotient = a / 2n; // Забележка: Делението закръглява към нула
const remainder = a % 7n;
const power = a ** 3n; // Степенуването работи както се очаква
console.log("Сума:", sum); // Изход: Сума: 111111111011111111100n
console.log("Разлика:", difference); // Изход: Разлика: -86419753208641975320n
console.log("Произведение:", product); // Изход: Произведение: 1219326311370217957951669538098765432100n
console.log("Частно:", quotient); // Изход: Частно: 6172839450617283945n
console.log("Остатък:", remainder); // Изход: Остатък: 5n
console.log("Степен:", power); // Изход: Степен: 187641281029182300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n
Важни съображения:
- Деление: Делението с
BigInt
стойности закръглява към нула. Това означава, че дробната част от резултата се премахва. Ако се нуждаете от по-прецизно деление, обмислете използването на библиотеки, които поддържат аритметика с произволна точност. - Унарен плюс оператор (+): Унарният плюс оператор (+) не може да се използва с
BigInt
стойности, защото би влязъл в конфликт със стар asm.js код. Използвайте функцията за преобразуване `Number()`, за да преобразувате BigInt в Number, ако се нуждаете от числово представяне (с разбирането, че може да загубите прецизност). - Побитови оператори:
BigInt
също поддържа побитови оператори като `&`, `|`, `^`, `~`, `<<` и `>>`. Тези оператори работят както се очаква върху двоичното представяне наBigInt
стойностите.
Оператори за сравнение
Можете да използвате стандартни оператори за сравнение (`==`, `!=`, `<`, `>`, `<=`, `>=`), за да сравнявате BigInt
стойности с други BigInt
стойности или дори с Number
стойности. Въпреки това, имайте предвид потенциала за преобразуване на типове.
Примери:
const a = 10n;
const b = 20n;
const c = 10;
console.log(a == b); // Изход: false
console.log(a != b); // Изход: true
console.log(a < b); // Изход: true
console.log(a > b); // Изход: false
console.log(a <= b); // Изход: true
console.log(a >= b); // Изход: false
console.log(a == c); // Изход: true (преобразуване на типове)
console.log(a === c); // Изход: false (няма преобразуване на типове)
Добра практика: Използвайте стриктно равенство (`===`) и стриктно неравенство (`!==`), за да избегнете неочаквано преобразуване на типове при сравняване на BigInt
и Number
стойности.
Преобразуване между BigInt и Number
Въпреки че директните аритметични операции между BigInt
и Number
не са позволени, можете да преобразувате между двата типа. Все пак, имайте предвид потенциалната загуба на прецизност при преобразуване на BigInt
в Number
, ако стойността на BigInt
надвишава `Number.MAX_SAFE_INTEGER`.
Примери:
const bigIntValue = 9007199254740991n; // Number.MAX_SAFE_INTEGER
const numberValue = Number(bigIntValue); // Преобразуване на BigInt в Number
console.log(numberValue); // Изход: 9007199254740991
const largerBigIntValue = 9007199254740992n; // Надхвърля Number.MAX_SAFE_INTEGER
const largerNumberValue = Number(largerBigIntValue);
console.log(largerNumberValue); // Изход: 9007199254740992 (може да е неточно)
const numberToBigInt = BigInt(12345); // Преобразуване на Number в BigInt
console.log(numberToBigInt); // Изход: 12345n
Случаи на употреба и примери
Криптография
Криптографските алгоритми често разчитат на много големи прости числа за сигурност. BigInt
предоставя начин за ефективно представяне и манипулиране на тези числа.
// Пример: Генериране на проста (несигурна) двойка ключове
function generateKeyPair() {
const p = 281n; // Просто число
const q = 283n; // Друго просто число
const n = p * q; // Модул
const totient = (p - 1n) * (q - 1n); // Функция на Ойлер
// Изберете e (публичен експонент), така че 1 < e < totient и gcd(e, totient) = 1
const e = 17n;
// Изчислете d (частен експонент), така че (d * e) % totient = 1
let d = 0n;
for (let i = 1n; i < totient; i++) {
if ((i * e) % totient === 1n) {
d = i;
break;
}
}
return {
publicKey: { n, e },
privateKey: { n, d },
};
}
const keyPair = generateKeyPair();
console.log("Публичен ключ:", keyPair.publicKey);
console.log("Частен ключ:", keyPair.privateKey);
Забележка: Това е опростен пример само за демонстрационни цели. Криптографията в реалния свят използва много по-големи прости числа и по-сложни алгоритми.
Финансови изчисления
При работа с големи суми пари, особено при международни транзакции, прецизността е от решаващо значение. BigInt
може да предотврати грешки при закръгляване и да осигури точни изчисления.
// Пример: Изчисляване на сложна лихва
function calculateCompoundInterest(principal, rate, time) {
const principalBigInt = BigInt(principal * 100); // Преобразуване в стотинки
const rateBigInt = BigInt(rate * 10000); // Преобразуване в десетохилядни от процента
const timeBigInt = BigInt(time);
let amount = principalBigInt;
for (let i = 0n; i < timeBigInt; i++) {
amount = amount * (10000n + rateBigInt) / 10000n;
}
const amountInDollars = Number(amount) / 100;
return amountInDollars;
}
const principal = 1000000; // $1,000,000
const rate = 0.05; // 5% лихвен процент
const time = 10; // 10 години
const finalAmount = calculateCompoundInterest(principal, rate, time);
console.log("Крайна сума:", finalAmount); // Изход: Крайна сума: 1628894.6267774413 (приблизително)
В този пример преобразуваме главницата и лихвения процент в BigInt
стойности, за да избегнем грешки при закръгляване по време на изчислението. След това резултатът се преобразува обратно в Number
за показване.
Работа с големи идентификатори (ID)
В разпределените системи генерирането на уникални ID-та на множество сървъри може да бъде предизвикателство. Използването на BigInt
ви позволява да създавате много големи ID-та, които е малко вероятно да се сблъскат.
// Пример: Генериране на уникален ID на базата на времеви маркер и ID на сървъра
function generateUniqueId(serverId) {
const timestamp = BigInt(Date.now());
const serverIdBigInt = BigInt(serverId);
const random = BigInt(Math.floor(Math.random() * 1000)); // Добавяне на малко случайност
// Комбинирайте стойностите, за да създадете уникален ID
const uniqueId = (timestamp << 20n) + (serverIdBigInt << 10n) + random;
return uniqueId.toString(); // Върнете като низ за лесна обработка
}
const serverId = 123; // Примерно ID на сървър
const id1 = generateUniqueId(serverId);
const id2 = generateUniqueId(serverId);
console.log("Уникален ID 1:", id1);
console.log("Уникален ID 2:", id2);
BigInt и JSON
Стойностите BigInt
не се поддържат нативно от JSON. Опитът да се сериализира JavaScript обект, съдържащ BigInt
, с помощта на `JSON.stringify()` ще доведе до `TypeError`. За да обработвате BigInt
стойности при работа с JSON, имате няколко възможности:
- Преобразуване в низ: Преобразувайте
BigInt
в низ преди сериализация. Това е най-често срещаният и лесен подход. - Персонализирана сериализация/десериализация: Използвайте персонализирана функция за сериализация/десериализация, за да обработвате
BigInt
стойности.
Примери:
Преобразуване в низ:
const data = {
id: 12345678901234567890n,
name: "Example Data",
};
// Преобразувайте BigInt в низ преди сериализация
data.id = data.id.toString();
const jsonData = JSON.stringify(data);
console.log(jsonData); // Изход: {"id":"12345678901234567890","name":"Example Data"}
// При десериализация ще трябва да преобразувате низа обратно в BigInt
const parsedData = JSON.parse(jsonData, (key, value) => {
if (key === "id") {
return BigInt(value);
}
return value;
});
console.log(parsedData.id); // Изход: 12345678901234567890n
Персонализирана сериализация/десериализация (с `replacer` и `reviver`):
const data = {
id: 12345678901234567890n,
name: "Example Data",
};
// Персонализирана сериализация
const jsonData = JSON.stringify(data, (key, value) => {
if (typeof value === 'bigint') {
return value.toString();
} else {
return value;
}
});
console.log(jsonData);
// Персонализирана десериализация
const parsedData = JSON.parse(jsonData, (key, value) => {
if (typeof value === 'string' && /^[0-9]+$/.test(value)) { //проверете дали е число и низ
try {
return BigInt(value);
} catch(e) {
return value;
}
}
return value;
});
console.log(parsedData.id);
Съвместимост с браузъри
BigInt
се поддържа широко в съвременните браузъри. Въпреки това е важно да се провери съвместимостта за по-стари браузъри или среди. Можете да използвате инструмент като Can I use, за да проверите поддръжката от браузърите. Ако трябва да поддържате по-стари браузъри, може да обмислите използването на полифил, но имайте предвид, че полифилите могат да повлияят на производителността.
Съображения относно производителността
Въпреки че BigInt
предоставя мощен начин за работа с големи цели числа, е важно да сте наясно с потенциалните последици за производителността.
- Операциите с
BigInt
могат да бъдат по-бавни от стандартните операции сNumber
. - Преобразуването между
BigInt
иNumber
също може да доведе до допълнително натоварване.
Следователно, използвайте BigInt
само когато е необходимо и оптимизирайте кода си за производителност, ако извършвате голям брой операции с BigInt
.
Заключение
BigInt
е ценно допълнение към JavaScript, което позволява на разработчиците да обработват аритметика с големи цели числа с прецизност. Като разбирате неговите характеристики, ограничения и случаи на употреба, можете да използвате BigInt
за изграждане на стабилни и точни приложения в различни области, включително криптография, финансови изчисления и научни изчисления. Не забравяйте да вземете предвид съвместимостта с браузърите и последиците за производителността, когато използвате BigInt
във вашите проекти.
За допълнително проучване
- Mozilla Developer Network (MDN) - BigInt
- V8 Blog - BigInt: Arbitrary-Precision Integers in JavaScript
Това ръководство предоставя изчерпателен преглед на BigInt
в JavaScript. Разгледайте свързаните ресурси за по-задълбочена информация и напреднали техники.