Back

Когда может понадобиться BigInt в JavaScript?

Когда может понадобиться BigInt в JavaScript?

JavaScript прекрасно справляется с большинством чисел — пока не перестаёт. Если вы когда-либо получали большой ID из API и замечали, что он возвращался слегка искажённым, или пытались выполнить точные арифметические операции с очень большим целым числом и получали незаметно неверный результат, вы уже сталкивались с проблемой, которую решает BigInt.

Ключевые моменты

  • Числа в JavaScript используют формат IEEE 754 с двойной точностью, что ограничивает безопасные целые числа диапазоном −(2⁵³ − 1) до 2⁵³ − 1. За его пределами значения теряют точность незаметно.
  • BigInt — это примитивный тип (введён в ES2020), который представляет целые числа произвольного размера, но не может работать с десятичными дробями.
  • Реальные сценарии использования включают обработку больших внешних ID (например, Twitter Snowflake ID), 64-битных целых чисел WebAssembly и точную арифметику для больших счётчиков или данных блокчейна.
  • BigInt нельзя смешивать с Number в выражениях, он не работает с API Math и требует специальной обработки для JSON-сериализации.

Предел, который числа JavaScript не могут преодолеть

Все числа в JavaScript используют формат IEEE 754 с двойной точностью с плавающей запятой. Это даёт вам безопасный диапазон целых чисел −(2⁵³ − 1) до 2⁵³ − 1, представленный константами Number.MIN_SAFE_INTEGER и Number.MAX_SAFE_INTEGER.

За пределами этой границы целые числа теряют точность незаметно:

console.log(9007199254740991 + 1)  // 9007199254740992 ✅
console.log(9007199254740991 + 2)  // 9007199254740992 ❌ (неверно)

// Это проблема точности в действии:
9007199254740992 === 9007199254740993 // true — для JavaScript они одинаковы

Ошибка не выбрасывается. Значение просто неверное. Это проблема ограничения точности, для решения которой был разработан BigInt.

Что такое BigInt на самом деле

BigInt — это встроенный примитивный тип JavaScript, введённый в ES2020, который может представлять целые числа произвольного размера, ограниченные только доступной памятью. Вы создаёте его, добавляя n к целочисленному литералу или используя конструктор BigInt():

const big = 9007199254740993n                 // синтаксис литерала
const alsoBig = BigInt("9007199254740993")    // конструктор со строкой

9007199254740992n === 9007199254740993n        // false ✅ — правильно

Одно важное ограничение: BigInt работает только с целыми числами. Он не может представлять десятичные или дробные значения. 1.5n вызывает SyntaxError.

Когда использовать BigInt в JavaScript

Большинству фронтенд-кода BigInt никогда не понадобится. Но есть несколько реальных сценариев, которые действительно требуют его использования.

Большие ID из внешних систем. Система Snowflake ID от Twitter и аналогичные схемы распределённых ID генерируют 64-битные целые числа, которые превышают Number.MAX_SAFE_INTEGER. Когда REST API возвращает такой ID как JSON-число, JavaScript незаметно исказит его. Парсинг его как строки и преобразование в BigInt сохраняет значение точно.

// 64-битный ID, полученный как строка из API
const userId = BigInt("922337203685477580")

64-битные целые числа из WebAssembly. Тип i64 в WebAssembly напрямую соответствует BigInt в JavaScript. Если ваш Wasm-модуль возвращает или принимает 64-битные целые числа, вам понадобится BigInt для корректной работы с ними.

Точная целочисленная арифметика, где точность никогда не должна теряться. Определённые значения транзакций блокчейна, большие счётчики или арифметика временных меток высокой точности (например, наносекунды с начала эпохи) могут превышать диапазон безопасных целых чисел. BigInt сохраняет каждую цифру точно.

Важные ограничения, которые нужно знать

Прежде чем использовать BigInt, поймите его ограничения:

Нельзя смешивать BigInt и Number в арифметических операциях. Это вызывает TypeError. Требуется явное преобразование:

const big = 10n
const num = 5

big + num            // ❌ TypeError
big + BigInt(num)    // ✅ 15n
Number(big) + num    // ✅ 15 (но теряет точность BigInt для больших значений)

API Math не работает с BigInt. Math.max(), Math.sqrt() и любой другой метод Math выбросят ошибку при передаче BigInt. Если вам нужны эти операции, придётся преобразовывать — и принять компромисс в точности.

JSON-сериализация по умолчанию не работает. JSON.stringify() выбрасывает TypeError для значений BigInt. Вам нужна пользовательская функция replacer или метод toJSON() для обработки сериализации:

BigInt.prototype.toJSON = function () {
  return this.toString()
}

JSON.stringify({ id: 922337203685477580n }) // '{"id":"922337203685477580"}'

Обратите внимание, что это преобразует значение в строку в JSON-выводе, что принимающая система должна соответствующим образом обработать. Также изменение встроенного прототипа вроде BigInt.prototype обычно не рекомендуется в production-коде. Более безопасная альтернатива — пользовательская функция replacer, передаваемая в JSON.stringify():

const data = { id: 922337203685477580n }

JSON.stringify(data, (key, value) =>
  typeof value === "bigint" ? value.toString() : value
) // '{"id":"922337203685477580"}'

Итог

BigInt против Number в JavaScript — это не совсем конкуренция, они служат разным целям. Используйте Number для всего, с чем он хорошо справляется, а это большинство вещей. Обращайтесь к BigInt конкретно тогда, когда вы работаете с целыми числами, которые могут превышать 2⁵³ − 1, и где корректность не подлежит обсуждению. Это узкая, но важная категория, и BigInt справляется с ней абсолютно правильно.

Часто задаваемые вопросы

BigInt поддерживается во всех современных браузерах, включая Chrome, Firefox, Safari и Edge. Однако Internet Explorer его не поддерживает. Если вам нужна поддержка IE, вам придётся хранить значения как строки или использовать библиотеку для работы с большими числами вместо нативного BigInt.

Да. Вы можете сравнивать значения BigInt с другими BigInt, используя стандартные операторы сравнения, такие как меньше, больше и строгое равенство. Вы также можете использовать нестрогое равенство для сравнения BigInt с Number, поэтому 10n == 10 возвращает true, но 10n === 10 возвращает false, потому что это разные типы.

Да. Операции с BigInt обычно медленнее операций с Number, потому что они используют арифметику произвольной точности, а не инструкции фиксированного размера на уровне процессора. Для большинства приложений разница незначительна, но в критичных по производительности циклах или горячих путях следует провести бенчмарки и предпочесть Number, когда значения остаются в диапазоне безопасных целых чисел.

Используйте конструктор Number, например Number(100n), который вернёт 100. Однако будьте осторожны с большими значениями. Если BigInt превышает Number.MAX_SAFE_INTEGER, преобразование незаметно потеряет точность. Всегда проверяйте, помещается ли значение в безопасный диапазон перед преобразованием.

Complete picture for complete understanding

Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Check our GitHub repo and join the thousands of developers in our community.

OpenReplay