JavaScript类型化数组是在Firefox 4和Chrome 7中实现的,它们是在JavaScript中存储和处理二进制数据的一种非常高效的方式。然而,当前的实现仅提供每个成员最多32位的整数视图,包括Int32Array
和Uint32Array
。是否计划实现64位整数视图?如何实现64位整数视图?它们的速度会慢多少?
JavaScript类型化数组是在Firefox 4和Chrome 7中实现的,它们是在JavaScript中存储和处理二进制数据的一种非常高效的方式。然而,当前的实现仅提供每个成员最多32位的整数视图,包括Int32Array
和Uint32Array
。是否计划实现64位整数视图?如何实现64位整数视图?它们的速度会慢多少?
ECMAScript 2020现在内置了BigInt
类型,还有 BigInt64Array
和 BigUint64Array
类型数组。这些数组的内部表示是64位,它们被转换为和从BigInt
值,这些值需要保留完整精度。
BigInt
和数组类型仍然相对较新,因此如果您需要支持旧的浏览器或Node版本,请参考下面内容。您可以使用诸如CanIUse.com之类的资源来查看要支持哪些浏览器,以帮助您决定是否可以使用这种选项。直到逐步淘汰不受支持的浏览器之前,Polyfills也可能是一种解决方法。
旧浏览器 / Node 环境的解决方案:
由于JavaScript中所有数字都是64位的浮点数字,只有53位精度,因此实现一个Int64Array
没有实际意义。正如Simeon在评论中所说,您可以使用一个大整数库,但速度会更慢。
如果您真的需要一个64位整数数组,不考虑性能,那么Google Closure库有一个64位的Long
类,我想它比更普遍的大整数库要快。但我从未使用过,并且不知道您是否可以轻松地将其与库的其余部分分开。
function getUint64(inputArray, index, littleEndian) {
const dataView = new DataView(inputArray.buffer);
let hi = dataView.getUint32(index, littleEndian);
let lo = dataView.getUint32(index + 4, littleEndian);
if (littleEndian) {
const tmp = hi;
hi = lo;
lo = tmp;
}
if (hi > 0x1fffff) {
throw new Error(
'Cannot safely parse uints over 2^53 - 1 (0x1fffffffffffff) in to a 64 bit float.'
);
}
const numberValue = (hi * 0x100000000) + lo;
return numberValue;
}
// Tests gotten from this other excellent answer here: https://dev59.com/jq_la4cB1Zd3GeqPuIVM#53107482
// [byteArray, littleEndian, expectedValue, expectError]
const testValues = [
// big-endian
[new Uint8Array([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff]), false, 255],
[new Uint8Array([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff]), false, 65535],
[new Uint8Array([0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff]), false, 4294967295],
[new Uint8Array([0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]), false, 4294967296],
[new Uint8Array([0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), false, 9007199254740991], // maximum precision
[new Uint8Array([0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), false, 9007199254740992, true], // precision lost
[new Uint8Array([0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01]), false, 9007199254740992, true], // precision lost
// little-endian
[new Uint8Array([0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), true, 255],
[new Uint8Array([0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), true, 65535],
[new Uint8Array([0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00]), true, 4294967295],
[new Uint8Array([0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00]), true, 4294967296],
[new Uint8Array([0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00]), true, 1099511627776],
[new Uint8Array([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00]), true, 281474976710656],
[new Uint8Array([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00]), true, 9007199254740991], // maximum precision
];
testValues.forEach(testGetUint64);
function testGetUint64([bytes, littleEndian, expectedValue, expectError]) {
if (expectError) {
try {
const val = getUint64(bytes, 0, littleEndian);
console.error('did not get the expected error');
} catch(error) {
console.log('got expected error: ' + error.message);
}
} else {
const val = getUint64(bytes, 0, littleEndian);
console.log(val === expectedValue? 'pass' : 'FAIL. expected '+expectedValue+', received '+val);
}
}
你可以使用 Float64Array
或者 Float32Array
。
但我不确定这是否符合你的需求,因为它是一个浮点数。
BigInt
提案现在已经进入了第三阶段(虽然晚了7年...)。 - tsh