BigInt
Clase 4 de 510 min de lectura
En la clase anterior vimos que number se queda sin precisión con los enteros muy grandes. BigInt es el primitivo que lo arregla: llegó en ES2020 (ES11) para representar enteros de tamaño arbitrario, tan grandes como aguante la memoria.
¿Por qué necesitamos BigInt?#
Porque con number, pasado cierto límite, las cuentas dejan de salir. Sigue este ejemplo línea a línea:
// Límite del tipo numberconst bigNumber = 30000000000000000console.log(bigNumber) // -> 30000000000000000// Si le sumáramos 1 a este número, el resultado debería ser:// 30000000000000001// Pero si lo intentas sumar con JS, el resultado es diferente:console.log(bigNumber + 1) // -> 30000000000000000console.log(bigNumber + 2) // -> 30000000000000000 (¡igual!)// Incluso con números grandes, puedes perder precisiónlet numeroGrande = 1234567890123456789console.log(numeroGrande) // -> 1234567890123456800 (¡redondeado!)Sumas y el número no se mueve. Con BigInt el problema desaparece. Fíjate en la n del final:
// Con BigInt mantenemos la precisiónlet numeroGrandeBigInt = 1234567890123456789nconsole.log(numeroGrandeBigInt) // -> 1234567890123456789n (¡exacto!)console.log(numeroGrandeBigInt + 1n) // -> 1234567890123456790n (¡exacto!)BigInt (el sufijo n) existen todos los enteros, sin límite: 9007199254740991n + 2n da el resultado exacto.Creación de BigInt#
Tienes dos formas de crear un BigInt: añadir el sufijo n al número o usar la función BigInt(). En ambos casos obtienes un primitivo, así que typeof devuelve 'bigint'.
1. Literal BigInt (sufijo 'n')
Escribes el entero y le pegas una n detrás:
// Enteros con sufijo 'n'let grande1 = 123nlet grande2 = 9007199254740991nlet grande3 = 1234567890123456789012345678901234567890nconsole.log(typeof grande1) // -> 'bigint'2. Constructor BigInt()
Cuando el valor te llega en una variable, pásaselo a BigInt(). Acepta un número entero o una cadena de texto, también en hexadecimal o binario:
// Desde número (si está en rango seguro)let desdeEntero = BigInt(123) // -> 123nlet desdeEnteroGrande = BigInt(9007199254740991) // -> 9007199254740991n// Desde stringlet desdeString = BigInt('123456789012345678901234567890')// -> 123456789012345678901234567890n// Desde string hexadecimallet desdeHex = BigInt('0x1fffffffffffff') // -> 9007199254740991n// Desde string binarialet desdeBin = BigInt('0b11111111111111111111111111111111') // -> 4294967295n// Desde una variablelet numeroGrandeEnString = '123456789012345678901234567890'let desdeVariable = BigInt(numeroGrandeEnString) // -> 123456789012345678901234567890n¿Por qué pasar un string si ya existen los números? Porque un number enorme ya habría perdido precisión antes de llegar a BigInt(). El texto, en cambio, conserva todos los dígitos.
3. Limitaciones en la creación
No todo se puede convertir en BigInt. Estos son los tres tropiezos típicos:
// ❌ No funciona con decimales// BigInt(3.14) // RangeError: The number 3.14 cannot be converted to a BigInt// ⚠️ Cuidado con números que ya están fuera del rango seguro de Number// BigInt(Number.MAX_SAFE_INTEGER + 2) // Puede dar resultados inesperados// ❌ No funciona con strings inválidos// BigInt("abc") // SyntaxError: Cannot convert abc to a BigIntOperaciones con BigInt#
Igual que los números, los BigInt admiten operadores aritméticos, de comparación y bitwise.
Operaciones aritméticas básicas
Todo funciona como esperas, con una excepción: la división descarta los decimales.
let a = 100nlet b = 200n// Operaciones básicasconsole.log(a + b) // -> 300nconsole.log(a - b) // -> -100nconsole.log(a * b) // -> 20000nconsole.log(b / a) // -> 2n (división entera)console.log(b % a) // -> 0n (módulo)console.log(a ** 2n) // -> 10000n (exponenciación)// ¡Ojo! La división siempre es entera, no te da los decimalesconsole.log(7n / 2n) // -> 3n (no 3.5)console.log(10n / 3n) // -> 3n (no 3.333...)Comparaciones
Entre BigInt no hay misterio. Lo interesante viene al compararlos con un number normal:
let x = 100nlet y = 200n// Comparaciones funcionan normalmenteconsole.log(x < y) // -> trueconsole.log(x > y) // -> falseconsole.log(x === 100n) // -> trueconsole.log(x !== y) // -> true// Comparación con números regularesconsole.log(100n == 100) // -> true (coerción)console.log(100n === 100) // -> false (tipos diferentes)console.log(100n < 101) // -> trueconsole.log(100n > 99) // -> true100n y 100 valen lo mismo, pero son de tipos distintos, por eso la igualdad estricta dice false. En cambio, < y > sí comparan por valor.
Operaciones bitwise
Las operaciones bitwise trabajan bit a bit. Son más avanzadas que las aritméticas, y con BigInt también funcionan:
let bits1 = 0b1010n // -> 10nlet bits2 = 0b1100n // -> 12n// Operadores bitwiseconsole.log(bits1 & bits2) // -> 8n (AND)console.log(bits1 | bits2) // -> 14n (OR)console.log(bits1 ^ bits2) // -> 6n (XOR)console.log(~bits1) // -> -11n (NOT)console.log(bits1 << 2n) // -> 40n (shift left)console.log(bits1 >> 1n) // -> 5n (shift right)Restricciones importantes#
BigInt es otro tipo, y no siempre encaja donde encajaba un number. Hay tres sitios donde vas a chocar, y el primero es el que más problemas da.
No se puede mezclar con Number
Si juntas un BigInt y un number en una operación aritmética, JavaScript lanza un error:
100n + 50Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversionsEl propio error te da la solución: decide tú a qué tipo conviertes.
let bigint = 100nlet number = 50// ❌ Esto no funciona// console.log(bigint + number) // TypeError: Cannot mix BigInt and other types// ✅ Hay que convertir explícitamenteconsole.log(bigint + BigInt(number)) // -> 150nconsole.log(Number(bigint) + number) // -> 150// ✅ O usar comparaciones que permiten coerciónconsole.log(bigint > number) // -> trueNo funciona con Math
Los métodos de Math están pensados para number y rechazan los BigInt:
let grande = 100n// ❌ Math no acepta BigInt// Math.sqrt(grande) // TypeError: Cannot convert a BigInt value to a number// Math.max(10n, 20n) // TypeError// ✅ Usa operaciones nativas de BigIntconsole.log(grande ** 2n) // -> 10000n para potenciasNo se puede usar con JSON
JSON.stringify() no sabe qué hacer con un BigInt. La salida es convertirlo antes a string:
let objeto = { numero: 42, grande: 123n}// ❌ JSON.stringify no maneja BigInt// JSON.stringify(objeto) // TypeError: Do not know how to serialize a BigInt// ✅ Solución: convertir a stringlet objetoSerializable = { numero: objeto.numero, grande: objeto.grande.toString()}console.log(JSON.stringify(objetoSerializable))// -> {"numero":42,"grande":"123"}Métodos de BigInt#
Métodos estáticos
Dos métodos para encajar un valor en un número concreto de bits. Lo que no cabe, se recorta:
// BigInt.asIntN() - convierte a entero con signo de N bitsconsole.log(BigInt.asIntN(8, 300n)) // -> 44n (300 en 8 bits con signo)// BigInt.asUintN() - convierte a entero sin signo de N bitsconsole.log(BigInt.asUintN(8, 300n)) // -> 44n (300 en 8 bits sin signo)console.log(BigInt.asUintN(8, -1n)) // -> 255n (-1 en 8 bits sin signo)Conversiones#
De BigInt a otros tipos
let grande = 123456789n// A Number (cuidado con la precisión)let comoNumber = Number(grande) // -> 123456789console.log(typeof comoNumber) // -> 'number'// A Stringlet comoString = String(grande) // -> '123456789'let comoStringDirect = grande.toString() // -> '123456789'// A Booleanlet comoBoolean = Boolean(grande) // -> trueconsole.log(Boolean(0n)) // -> falseDe otros tipos a BigInt
// Desde Number (solo enteros en rango seguro)let desdeNumber = BigInt(42) // -> 42n// Desde Stringlet desdeString = BigInt('123456789012345678901234567890')// Desde Booleanlet desdeTrue = BigInt(true) // -> 1nlet desdeFalse = BigInt(false) // -> 0nEn resumen
BigIntrepresenta enteros de cualquier tamaño sin perder precisión, más allá deNumber.MAX_SAFE_INTEGER.- Se crea con el sufijo
n(123n) o conBigInt(). - Solo enteros: no admite decimales y la división descarta el resto.
- No se mezcla con
Numberen operaciones aritméticas: convierte explícitamente. - No funciona con
Mathni se serializa en JSON.
Palabras finales sobre BigInt#
No vas a necesitar BigInt todos los días. Suele aparecer en criptografía o en temas financieros, donde no te puedes permitir perder información al operar con números muy grandes. Y recuerda que los navegadores antiguos no lo soportan.