TypedArray
一个TypedArray对象描述了底层二进制数据缓冲区的类似数组的视图。没有名为TypedArray
的全局属性,也没有直接可见的TypedArray
构造函数。相反,有一些不同的全局属性,其值是针对特定元素类型的类型化数组构造函数,如下所示。在以下页面中,您将找到可用于包含任何类型元素的任何类型化数组的通用属性和方法。
试一试
描述
TypedArray
构造函数(通常称为%TypedArray%
以指示其“内在性”,因为它不对应于向 JavaScript 程序公开的任何全局变量)充当所有TypedArray
子类的通用超类。将%TypedArray%
视为一个“抽象类”,为所有类型化数组子类提供通用实用程序方法接口。此构造函数不会直接公开:没有全局TypedArray
属性。它只能通过Object.getPrototypeOf(Int8Array)
等方式访问。
在创建TypedArray
子类的实例(例如Int8Array
)时,会在内存中内部创建数组缓冲区,或者如果将ArrayBuffer
对象作为构造函数参数给出,则使用该ArrayBuffer
。缓冲区地址被保存为实例的内部属性,并且%TypedArray%.prototype
的所有方法都将根据该数组缓冲区地址设置和获取值。
TypedArray 对象
类型 | 值范围 | 大小(以字节为单位) | Web IDL 类型 |
---|---|---|---|
Int8Array |
-128 到 127 | 1 | 字节 |
Uint8Array |
0 到 255 | 1 | 八位字节 |
Uint8ClampedArray |
0 到 255 | 1 | 八位字节 |
Int16Array |
-32768 到 32767 | 2 | 短整型 |
Uint16Array |
0 到 65535 | 2 | 无符号短整型 |
Int32Array |
-2147483648 到 2147483647 | 4 | 长整型 |
Uint32Array |
0 到 4294967295 | 4 | 无符号长整型 |
Float16Array |
-65504 到 65504 |
2 | 不适用 |
Float32Array |
-3.4e38 到 3.4e38 |
4 | 不受限制的浮点数 |
Float64Array |
-1.8e308 到 1.8e308 |
8 | 不受限制的双精度浮点数 |
BigInt64Array |
-263 到 263 - 1 | 8 | 大整数 |
BigUint64Array |
0 到 264 - 1 | 8 | 大整数 |
值编码和规范化
所有类型化数组都操作ArrayBuffer
,您可以在其中观察每个元素的确切字节表示形式,因此数字如何在二进制格式中编码非常重要。
- 无符号整数数组(
Uint8Array
、Uint16Array
、Uint32Array
和BigUint64Array
)直接以二进制形式存储数字。 - 有符号整数数组(
Int8Array
、Int16Array
、Int32Array
和BigInt64Array
)使用二进制补码存储数字。 - 浮点数组(
Float16Array
、Float32Array
和Float64Array
)使用IEEE 754浮点格式存储数字。Number
参考包含有关确切格式的更多信息。JavaScript 数字默认使用双精度浮点格式,这与Float64Array
相同。Float32Array
使用 23 位(而不是 52 位)表示尾数,使用 8 位(而不是 11 位)表示指数。Float16Array
使用 10 位表示尾数,使用 5 位表示指数。请注意,规范要求所有NaN
值使用相同的位编码,但确切的位模式取决于实现。 Uint8ClampedArray
是一个特例。它像Uint8Array
一样以二进制形式存储数字,但是当您存储超出范围的数字时,它会通过数学值将数字钳位到 0 到 255 的范围,而不是截断最高有效位。
除Int8Array
、Uint8Array
和Uint8ClampedArray
之外的所有类型化数组都使用多个字节存储每个元素。这些字节可以按从最高有效位到最低有效位(大端)或从最低有效位到最高有效位(小端)的顺序排列。有关更多说明,请参阅Endianness。类型化数组始终使用平台的本机字节顺序。如果您想在写入和读取缓冲区时指定字节序,则应改用DataView
。
写入这些类型化数组时,超出可表示范围的值将被规范化。
- 所有整数数组(除了
Uint8ClampedArray
)都使用定宽数字转换,它首先截断数字的小数部分,然后取最低有效位。 Uint8ClampedArray
首先将数字钳位到 0 到 255 的范围(大于 255 的值变为 255,小于 0 的值变为 0)。然后它舍入(而不是向下取整)结果到最接近的整数,四舍五入到偶数;这意味着如果数字正好位于两个整数之间,则将其舍入到最接近的偶数整数。例如,0.5
变为0
,1.5
变为2
,2.5
变为2
。Float16Array
和Float32Array
执行“舍入到偶数”以将 64 位浮点数转换为 32 位和 16 位。这与由Math.fround()
和Math.f16round()
提供的算法相同。
查看可调整大小的缓冲区时的行为
当TypedArray
被创建为可调整大小的缓冲区的视图时,调整底层缓冲区的大小将对TypedArray
的大小产生不同的影响,具体取决于TypedArray
是否被构建为长度跟踪。
如果一个类型化数组是在没有指定大小的情况下创建的(省略第三个参数或传递undefined
),则该类型化数组将成为长度跟踪的,并且会自动调整大小以适应底层buffer
,当后者被调整大小时。
const buffer = new ArrayBuffer(8, { maxByteLength: 16 });
const float32 = new Float32Array(buffer);
console.log(float32.byteLength); // 8
console.log(float32.length); // 2
buffer.resize(12);
console.log(float32.byteLength); // 12
console.log(float32.length); // 3
如果使用第三个length
参数创建了一个特定大小的类型化数组,那么当后者增长时,它不会调整大小以包含buffer
。
const buffer = new ArrayBuffer(8, { maxByteLength: 16 });
const float32 = new Float32Array(buffer, 0, 2);
console.log(float32.byteLength); // 8
console.log(float32.length); // 2
console.log(float32[0]); // 0, the initial value
buffer.resize(12);
console.log(float32.byteLength); // 8
console.log(float32.length); // 2
console.log(float32[0]); // 0, the initial value
当buffer
缩小时,查看的类型化数组可能会超出范围,在这种情况下,类型化数组的观察到的尺寸将减小到0。这是唯一一个非长度跟踪类型化数组的长度可能会改变的情况。
const buffer = new ArrayBuffer(8, { maxByteLength: 16 });
const float32 = new Float32Array(buffer, 0, 2);
buffer.resize(7);
console.log(float32.byteLength); // 0
console.log(float32.length); // 0
console.log(float32[0]); // undefined
如果然后再次增大buffer
以使类型化数组回到范围内,则类型化数组的大小将恢复到其原始值。
buffer.resize(8);
console.log(float32.byteLength); // 8
console.log(float32.length); // 2
console.log(float32[0]); // 0 - back in bounds again!
如果缓冲区缩小到超出byteOffset
,长度跟踪的类型化数组也会发生同样的情况。
const buffer = new ArrayBuffer(8, { maxByteLength: 16 });
const float32 = new Float32Array(buffer, 4);
// float32 is length-tracking, but it only extends from the 4th byte
// to the end of the buffer, so if the buffer is resized to be shorter
// than 4 bytes, the typed array will become out of bounds
buffer.resize(3);
console.log(float32.byteLength); // 0
构造函数
此对象无法直接实例化——尝试使用new
构造它会抛出一个TypeError
。
new (Object.getPrototypeOf(Int8Array))();
// TypeError: Abstract class TypedArray not directly constructable
相反,您可以创建一个特定类型的类型化数组的实例,例如Int8Array
或BigInt64Array
。这些对象都具有其构造函数的通用语法。
new TypedArray()
new TypedArray(length)
new TypedArray(typedArray)
new TypedArray(object)
new TypedArray(buffer)
new TypedArray(buffer, byteOffset)
new TypedArray(buffer, byteOffset, length)
其中TypedArray
是其中一个具体类型的构造函数。
参数
typedArray
-
当使用
TypedArray
子类的实例调用时,typedArray
会被复制到一个新的类型化数组中。对于非bigint的TypedArray
构造函数,typedArray
参数只能是其中一个非bigint类型(例如Int32Array
)。类似地,对于bigint的TypedArray
构造函数(BigInt64Array
或BigUint64Array
),typedArray
参数只能是其中一个bigint类型。每个typedArray
中的值在被复制到新数组之前都会转换为构造函数的相应类型。新类型化数组的长度将与typedArray
参数的长度相同。 object
-
当使用不是
TypedArray
实例的对象调用时,会以与TypedArray.from()
方法相同的方式创建一个新的类型化数组。 length
可选-
当使用非对象调用时,该参数将被视为一个数字,指定类型化数组的长度。在内存中创建一个内部数组缓冲区,大小为
length
乘以BYTES_PER_ELEMENT
字节,并填充零。省略所有参数等效于使用0
作为length
。 buffer
,byteOffset
可选,length
可选-
当使用
ArrayBuffer
或SharedArrayBuffer
实例调用时,并可选地使用byteOffset
和length
参数,则会创建一个新的类型化数组视图,该视图查看指定的缓冲区。byteOffset
(以字节为单位)和length
(以元素数量为单位,每个元素占用BYTES_PER_ELEMENT
字节)参数指定将由类型化数组视图公开的内存范围。如果两者都省略,则查看所有buffer
;如果只省略length
,则查看从byteOffset
开始的buffer
的剩余部分。如果省略length
,则类型化数组将变为长度跟踪。
异常
所有TypeArray
子类构造函数都以相同的方式操作。它们都会抛出以下异常。
TypeError
-
在以下情况之一中抛出
- 传递了一个
typedArray
,但它是一个bigint类型,而当前构造函数不是,反之亦然。 - 传递了一个
typedArray
,但它正在查看的缓冲区已分离,或者直接传递了一个已分离的buffer
。
- 传递了一个
RangeError
-
在以下情况之一中抛出
- 新类型化数组的长度过大。
buffer
的长度(如果未指定length
参数)或byteOffset
不是新类型化数组元素大小的整数倍。byteOffset
不是有效的数组索引(介于0和253 - 1之间的整数)。- 从缓冲区创建视图时,边界超出缓冲区。换句话说,
byteOffset + length * TypedArray.BYTES_PER_ELEMENT > buffer.byteLength
。
静态属性
这些属性在TypedArray
构造函数对象上定义,因此由所有TypedArray
子类构造函数共享。
TypedArray[Symbol.species]
-
用于创建派生对象的构造函数。
所有TypedArray
子类还具有以下静态属性。
TypedArray.BYTES_PER_ELEMENT
-
返回不同
TypedArray
对象的元素大小的数值。
静态方法
这些方法在TypedArray
构造函数对象上定义,因此由所有TypedArray
子类构造函数共享。
TypedArray.from()
-
从类数组或可迭代对象创建一个新的
TypedArray
。另请参见Array.from()
。 TypedArray.of()
-
使用可变数量的参数创建一个新的
TypedArray
。另请参见Array.of()
。
实例属性
这些属性在TypedArray.prototype
上定义,并由所有TypedArray
子类实例共享。
TypedArray.prototype.buffer
-
返回类型化数组引用的
ArrayBuffer
。 TypedArray.prototype.byteLength
-
返回类型化数组的长度(以字节为单位)。
TypedArray.prototype.byteOffset
-
返回类型化数组与其
ArrayBuffer
开头之间的偏移量(以字节为单位)。 TypedArray.prototype.constructor
-
创建实例对象的构造函数。
TypedArray.prototype.constructor
是隐藏的TypedArray
构造函数,但每个类型化数组子类也定义了自己的constructor
属性。 TypedArray.prototype.length
-
返回类型化数组中保存的元素数量。
TypedArray.prototype[Symbol.toStringTag]
-
TypedArray.prototype[Symbol.toStringTag]
属性的初始值为一个getter,它返回与类型化数组构造函数名称相同的字符串。如果this
值不是类型化数组子类之一,则返回undefined
。此属性用于Object.prototype.toString()
。但是,因为TypedArray
也有自己的toString()
方法,所以除非您使用类型化数组作为thisArg
调用Object.prototype.toString.call()
,否则不会使用此属性。
所有TypedArray
子类还具有以下实例属性。
TypedArray.prototype.BYTES_PER_ELEMENT
-
返回不同
TypedArray
对象的元素大小的数值。
实例方法
这些方法在TypedArray
原型对象上定义,因此由所有TypedArray
子类实例共享。
TypedArray.prototype.at()
-
获取一个整数并返回该索引处的项目。此方法允许使用负整数,这些整数从最后一个项目开始倒数。
TypedArray.prototype.copyWithin()
-
复制数组内的一系列数组元素。另请参见
Array.prototype.copyWithin()
。 TypedArray.prototype.entries()
-
返回一个新的数组迭代器对象,其中包含数组中每个索引的键/值对。另请参见
Array.prototype.entries()
。 TypedArray.prototype.every()
-
测试数组中所有元素是否都通过函数提供的测试。另请参见
Array.prototype.every()
。 TypedArray.prototype.fill()
-
使用静态值填充数组从起始索引到结束索引的所有元素。另请参见
Array.prototype.fill()
。 TypedArray.prototype.filter()
-
创建一个新数组,其中包含此数组中所有使提供的过滤函数返回
true
的元素。另请参见Array.prototype.filter()
。 TypedArray.prototype.find()
-
返回数组中第一个满足提供的测试函数的
element
,如果未找到合适的元素,则返回undefined
。另请参见Array.prototype.find()
。 TypedArray.prototype.findIndex()
-
返回数组中第一个具有满足提供的测试函数的元素的索引值,如果未找到合适的元素,则返回
-1
。另请参见Array.prototype.findIndex()
。 TypedArray.prototype.findLast()
-
返回数组中最后一个满足提供的测试函数的元素的值,如果未找到合适的元素,则返回
undefined
。另请参见Array.prototype.findLast()
。 TypedArray.prototype.findLastIndex()
-
返回数组中最后一个满足提供的测试函数的元素的索引,如果未找到合适的元素,则返回
-1
。另请参见Array.prototype.findLastIndex()
。 TypedArray.prototype.forEach()
-
为数组中的每个元素调用一个函数。另请参见
Array.prototype.forEach()
。 TypedArray.prototype.includes()
-
确定类型化数组是否包含某个元素,根据情况返回
true
或false
。另请参见Array.prototype.includes()
。 TypedArray.prototype.indexOf()
-
返回数组中等于指定值的元素的第一个(最小)索引,如果未找到则返回
-1
。另请参见Array.prototype.indexOf()
。 TypedArray.prototype.join()
-
将数组的所有元素连接成一个字符串。另请参见
Array.prototype.join()
。 TypedArray.prototype.keys()
-
返回一个新的数组迭代器,其中包含数组中每个索引的键。另请参见
Array.prototype.keys()
。 TypedArray.prototype.lastIndexOf()
-
返回数组中等于指定值的元素的最后一个(最大)索引,如果未找到则返回
-1
。另请参见Array.prototype.lastIndexOf()
。 TypedArray.prototype.map()
-
创建一个新数组,其中包含对该数组中每个元素调用提供的函数的结果。另请参见
Array.prototype.map()
。 TypedArray.prototype.reduce()
-
将函数应用于累加器和数组的每个值(从左到右),以将其减少为单个值。另请参见
Array.prototype.reduce()
。 TypedArray.prototype.reduceRight()
-
将函数应用于累加器和数组的每个值(从右到左),以将其减少为单个值。另请参见
Array.prototype.reduceRight()
。 TypedArray.prototype.reverse()
-
反转数组元素的顺序——第一个变为最后一个,最后一个变为第一个。另请参见
Array.prototype.reverse()
。 TypedArray.prototype.set()
-
将多个值存储到类型化数组中,从指定的数组读取输入值。
TypedArray.prototype.slice()
-
提取数组的一部分并返回一个新数组。另请参阅
Array.prototype.slice()
。 TypedArray.prototype.some()
-
如果此数组中的至少一个元素满足提供的测试函数,则返回
true
。另请参阅Array.prototype.some()
。 TypedArray.prototype.sort()
-
对数组的元素进行就地排序并返回该数组。另请参阅
Array.prototype.sort()
。 TypedArray.prototype.subarray()
-
从给定的开始和结束元素索引返回一个新的
TypedArray
。 TypedArray.prototype.toLocaleString()
-
返回表示数组及其元素的本地化字符串。另请参阅
Array.prototype.toLocaleString()
。 TypedArray.prototype.toReversed()
-
返回一个新数组,其中元素按相反顺序排列,而不修改原始数组。
TypedArray.prototype.toSorted()
-
返回一个新数组,其中元素按升序排列,而不修改原始数组。
TypedArray.prototype.toString()
-
返回表示数组及其元素的字符串。另请参阅
Array.prototype.toString()
。 TypedArray.prototype.values()
-
返回一个新的数组迭代器对象,其中包含数组中每个索引的值。另请参阅
Array.prototype.values()
。 TypedArray.prototype.with()
-
返回一个新数组,其中给定索引处的元素被替换为给定值,而不修改原始数组。
TypedArray.prototype[Symbol.iterator]()
-
返回一个新的数组迭代器对象,其中包含数组中每个索引的值。
示例
属性访问
您可以使用标准数组索引语法(即,使用方括号表示法)引用数组中的元素。但是,获取或设置类型化数组上的索引属性不会在此属性的原型链中搜索,即使索引超出范围也是如此。索引属性将查询ArrayBuffer
,并且永远不会查看对象属性。您仍然可以使用命名属性,就像所有对象一样。
// Setting and getting using standard array syntax
const int16 = new Int16Array(2);
int16[0] = 42;
console.log(int16[0]); // 42
// Indexed properties on prototypes are not consulted (Fx 25)
Int8Array.prototype[20] = "foo";
new Int8Array(32)[20]; // 0
// even when out of bound
Int8Array.prototype[20] = "foo";
new Int8Array(8)[20]; // undefined
// or with negative integers
Int8Array.prototype[-1] = "foo";
new Int8Array(8)[-1]; // undefined
// Named properties are allowed, though (Fx 30)
Int8Array.prototype.foo = "bar";
new Int8Array(32).foo; // "bar"
无法冻结
非空的 TypedArray
无法冻结,因为可以通过缓冲区的另一个 TypedArray
视图修改其底层的 ArrayBuffer
。这意味着该对象永远不会真正被冻结。
const i8 = Int8Array.of(1, 2, 3);
Object.freeze(i8);
// TypeError: Cannot freeze array buffer views with elements
ByteOffset 必须对齐
当将 TypedArray
构建为 ArrayBuffer
的视图时,byteOffset
参数必须与其元素大小对齐;换句话说,偏移量必须是 BYTES_PER_ELEMENT
的倍数。
const i32 = new Int32Array(new ArrayBuffer(4), 1);
// RangeError: start offset of Int32Array should be a multiple of 4
const i32 = new Int32Array(new ArrayBuffer(4), 0);
ByteLength 必须对齐
与 byteOffset
参数类似,传递给 TypedArray
构造函数的 ArrayBuffer
的 byteLength
属性必须是构造函数的 BYTES_PER_ELEMENT
的倍数。
const i32 = new Int32Array(new ArrayBuffer(3));
// RangeError: byte length of Int32Array should be a multiple of 4
const i32 = new Int32Array(new ArrayBuffer(4));
规范
规范 |
---|
ECMAScript 语言规范 # sec-typedarray-objects |
浏览器兼容性
BCD 表仅在浏览器中加载