ES10 中 BigInt 类型处理大数值的应用和实用技巧

在前端开发中,我们常常需要处理大量数值。在传统的 JavaScript 中,数值类型只能表现最大为 Number.MAX_SAFE_INTEGER(2^53-1)的整数值,而 ES10 中新增加的 BigInt 类型则可以处理任意大的整数值,大大提高了前端开发的精度和灵活性。

在本文中,我们将介绍 BigInt 类型的基本用法、注意事项和一些实用技巧,以及如何在项目中充分利用 BigInt 类型的优势。

一、BigInt 类型的基本用法

1.1 基础语法

BigInt 类型的语法很简单,只需要在整数后面加上一个 n 即可。例如:

const number = 123456789012345678901n;

需要注意的是,不能在 BigInt 值前使用 0b0o0x(二进制、八进制或十六进制等进制数值开头的标识),因为 BigInt 是用十进制表示的。

1.2 基本运算

大多数算术运算符和方法都能与 BigInt 类型一起使用,如 +-*/%**++--Math.abs() 等。不过需要注意,满足下列两个条件时,BigInt 才能与其他类型进行运算:

  • 两个运算数必须都是 BigInt 类型;
  • 对于除法运算 /,结果必须是整数值(向下取整)。
const a = 123456789012345678901n;
const b = 98765432109876543210n;

// 加减乘除
console.log(a + b); // 222222221122222222111n
console.log(a - b); // 24791356702469135791n
console.log(a * b); // 121932632275404633313965074342618703010n
console.log(a / b); // 1n

// 求余数与指数
console.log(a % b); // 1234567901234567901n
console.log(a ** 2n); // 152415787532388367504953515625361987875019051084662812499420218813121n

1.3 转换为 BigInt 类型

BigInt() 可以将一个普通的数值或字符串转换为 BigInt 类型。需要注意的是,这个函数只能用于在 NumberString 能够表达的范围内。

console.log(BigInt(123)); // 123n
console.log(BigInt("123456789012345678901")); // 123456789012345678901n

1.4 与 Number 类型转换

BigInt 类型和 Number 类型之间转换时需要注意,如果 BigInt 大于或等于 Number.MAX_SAFE_INTEGER ,则会发生截断。

const a = 12345678901234567890n;

console.log(Number(a)); // 12345678901234567890
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991

console.log(BigInt(Number.MAX_SAFE_INTEGER)); // 9007199254740991n
console.log(BigInt(Number.MAX_SAFE_INTEGER + 1)); // 9007199254740992n

1.5 使用位运算符

BigInt 类型可以和 Number 类型一起使用,但是不支持位运算符。不过,ES10 中新增了三个用于 BigInt 类型的位运算符:&n|n^n。例如:

const a = 12345678901234567890n;
const b = 56789012345678901234n;

console.log(a & b); // 475092313240332738
console.log(a | b); // 67134772522955157006n
console.log(a ^ b); // 67134772522955157006n

二、注意事项

虽然 BigInt 类型可以处理任意大的整数值,但是在使用时需要注意下列几点:

2.1 不支持隐式转换

Number 类型可以随时隐式转换为 String 类型,也可以作为数组索引等随意转换为 String 类型,但是 BigInt 类型不支持隐式转换,需要显式调用 toString() 方法。例如:

const a = 12345678901234567890n;

// 错误的写法
console.log("value is" + a); // TypeError: Cannot convert a BigInt value to a string

// 正确的写法
console.log("value is" + a.toString()); // value is 12345678901234567890

2.2 与普通对象互操作

尽管 BigInt 是一种类型安全的数值类型,但是不能直接与普通对象进行互操作:

const a = 12345678901234567890n;

// 错误写法
console.log(a + {}); // TypeError: Cannot convert object to primitive value

// 正确写法
console.log(a + BigInt(Object.prototype.valueOf.call({}))); // 12345678901234567890n

2.3 与 JSON 互操作

在 JavaScript 中,JSON.parse()JSON.stringify() 是两个非常常用的处理 JSON 数据的方法。但是由于 JSON 规范并不支持 BigInt 类型,因此 BigInt 类型和 JSON 一起使用时需要特别注意。

具体做法是自定义 JSON 序列化和反序列化方法,例如:

const a = {
  number: 123456789012345678901n
};

const string = JSON.stringify(a, function(key, value) {
  return typeof value === "bigint" ? value.toString() : value;
});

const parsed = JSON.parse(string, function(key, value) {
  return typeof value === "string" && /^\d+n$/.test(value) ? BigInt(value.slice(0, -1)) : value;
});

console.log(parsed.number); // 123456789012345678901n

三、实用技巧

下面我们介绍几个实用技巧,帮助读者充分利用 BigInt 类型的优势。

3.1 处理高精度计算

在普通 JavaScript 中,大多数高精度计算的解决方案都需要用到字符串,或者使用第三方库,比如 big.js。而有了 BigInt 类型之后,我们就可以不依赖于字符串和第三方库来处理高精度计算。

例如,求出斐波那契数列的第 n 项,可以使用递归和循环两种方法:

// 递归
function fibonacciRecursive(n) {
  if (n === 0n) return 0n;
  if (n === 1n) return 1n;
  return fibonacciRecursive(n - 1n) + fibonacciRecursive(n - 2n); 
}

console.log(fibonacciRecursive(100n)); // 354224848179261915075n

// 迭代
function fibonacciLoop(n) {
  let [a, b] = [0n, 1n];
  while (n--) {
    [a, b] = [b, a + b];
  }
  return a;
}

console.log(fibonacciLoop(100n)); // 354224848179261915075n

可以看到,在 BigInt 类型的支持下,递归和循环两种方法都可以在瞬间完成计算。

3.2 解决位运算问题

在普通 JavaScript 中,由于只支持 32 位的位运算符,很难解决一些和位运算有关的问题。比如,要求数组中所有数字的异或结果,可以使用 reduce() 和位运算符 ^ 进行求解:

const nums = [1, 2, 3, 4, 5, 4, 3, 2, 1];

const result = nums
  .map(num => BigInt(num))
  .reduce((acc, cur) => acc ^ cur, 0n)

console.log(result); // 0n

3.3 解决类型检测问题

在普通 JavaScript 中,要判断一个值是否为整数有很多种方法,比如使用 Number.isFinite()Math.floor()。不过,有了 BigInt 类型之后,我们可以直接使用 typeof 进行类型检测。

function isInt(value) {
  return typeof value === "bigint";
}

console.log(isInt(123456789012345678901n)); // true
console.log(isInt(123456789012345678901)); // false

四、总结

ES10 中的 BigInt 类型带来了前所未有的精度和灵活性,使得前端开发可以更加自由地处理数据。虽然在使用时需要特别注意隐式转换和与普通对象的互操作,但是只要掌握了基本用法和一些实用技巧,就可以轻松解决高精度问题、位运算问题和类型检测问题,提高代码的可读性和可维护性。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65ab5cb4add4f0e0ff500285


纠错反馈