JavaScript 中可以很方便在字符串和数字之间进行转换,比如:+'123'
=> 123
,(123).toString()
=> '123'
。
然而,需要注意的一点是,JavaScript 中的数字并不是整数,而是浮点数。更确切的说,数字使用的是 64 bit 双精度浮点数来表示的。这意味着,如果服务器存储的数字是一个 Int64,那么在给到前端的时候,很有可能会出现转化上的问题。对于双精度浮点数来说,能够表示的最大的数是 ,超过的部分就会被截断,无法精确表示。
比如:
console.log(+'9223372036854775808');
console.log(2 ** 63)
// output: 9223372036854776000
JavaScript 提供了 Number.isSafeInteger
这个 API 来判断一个数字是否是在可表示的安全范围内。比如:
console.log(Number.isSafeInteger(2 ** 63));
// output: false
console.log(Number.isSafeInteger(9223372036854776000));
// output: false
console.log(Number.isSafeInteger(2 ** 53 - 1));
// output: true
这里,2 ** 53 - 1
就是 JavaScript 中可以表示的最大整数,Number.MAX_SAFE_INTEGER
这个常量也等于这个值。超过这个数值的所有值都会被认为是不安全的,哪怕该值实际表示的结果“凑巧”是正确的。上例中,9223372036854776000
这个数字的表示结果“刚好”就是 9223372036854776000
本身,但是因为这个数已经超过了 ,所以依然被判定为是不安全的。
虽然 JavaScript 本身的数字不支持大数,但是 Chrome 已经集成了 BigInt
数据类型,它可以被用于表示任意大的整形数字,可以用于这样的使用场景。(注:BigInt
本身还在 staging 3,并不是标准的一部分)
简单的使用方法如下:
const num = BigInt(2 ** 63);
// or:
// const num = BigInt('9223372036854776000');
console.log(num);
// output: 9223372036854775808n
console.log(typeof num);
// output: bigint
需要注意的是,BigInt
不可以使用 new
运算符,否则会报错。直接像函数一样传递参数调用就可以了。
BigInt
也是支持数字运算的,运算的结果依然是 BigInt
:
console.log(1n + 2n); // => 3n
console.log(3n - 1n); // => 2n
console.log(2n * 3n); // => 6n
console.log(5n / 2n); // => 2n
特别需要注意的是,因为是整型数字之间的转换,所以在做除法的时候,不会出现小数。在上面的例子中,5n
和 2n
的除法,结果是 2n
而不是 2.5
,这一个行为和 C 中两个 Integer 之间除法的行为是一致的。
另外,BigInt
不支持和其他的数据类型进行混合计算。比如:1n + 2
这样的计算是会报错的,需要显式的进行类型转换后,才可以进行运算。这一点,和 JavaScript 中其他数据类型之间随意混乱的运算行为是不同的(比如,1 + '2'
这样的计算 JavaScript 就不会报错,还会得到 '12'
这样怪异的结果)。
虽然 BigInt
不允许和一般的 Number
进行混合计算,但是比较运算符是可以在两者之间进行比较的。比如:1n < 2
或 2n > 1
这些都是成立的。BigInt
和 Number
之间无法取得 ===
的严格等价关系,但是 ==
的比较是可能成立的。换句话说:1n == 1
是成立的,但是 1n === 1
是不成立的。
更多关于 BigInt
的行为,可以参考 MDN。