TypedArray

TypedArray 对象描述了底层 二进制数据缓冲区 的类似数组的视图。没有名为 TypedArray 的全局属性,也没有直接可见的 TypedArray 构造函数。相反,有许多不同的全局属性,其值是特定元素类型的类型化数组构造函数,如下所列。在接下来的几页中,你将找到可用于包含任何类型元素的任何类型化数组的常见属性和方法。

¥A TypedArray object describes an array-like view of an underlying binary data buffer. There is no global property named TypedArray, nor is there a directly visible TypedArray constructor. Instead, there are a number of different global properties, whose values are typed array constructors for specific element types, listed below. On the following pages you will find common properties and methods that can be used with any typed array containing elements of any type.

Try it

描述

¥Description

TypedArray 构造函数(通常称为 %TypedArray% 以指示其 "intrinsicness",因为它不对应于暴露给 JavaScript 程序的任何全局)充当所有 TypedArray 子类的公共超类。将 %TypedArray% 视为 "抽象类",为所有类型化数组子类提供实用方法的通用接口。这个构造函数没有直接暴露:没有全局 TypedArray 属性。它只能通过 Object.getPrototypeOf(Int8Array) 和类似的方式访问。

¥The TypedArray constructor (often referred to as %TypedArray% to indicate its "intrinsicness", since it does not correspond to any global exposed to a JavaScript program) serves as the common superclass of all TypedArray subclasses. Think about %TypedArray% as an "abstract class" providing a common interface of utility methods for all typed array subclasses. This constructor is not directly exposed: there is no global TypedArray property. It is only accessible through Object.getPrototypeOf(Int8Array) and similar.

创建 TypedArray 子类(例如 Int8Array)的实例时,会在内存中内部创建一个数组缓冲区,或者,如果将 ArrayBuffer 对象作为构造函数参数给出,则使用 ArrayBuffer 来代替。缓冲区地址被保存为实例的内部属性,%TypedArray%.prototype 的所有方法都将基于该数组缓冲区地址设置和获取值。

¥When creating an instance of a TypedArray subclass (e.g. Int8Array), an array buffer is created internally in memory or, if an ArrayBuffer object is given as constructor argument, that ArrayBuffer is used instead. The buffer address is saved as an internal property of the instance and all the methods of %TypedArray%.prototype will set and get values based on that array buffer address.

类型数组对象

¥TypedArray objects

类型 值范围 大小(以字节为单位) Web IDL 类型
Int8Array -128 至 127 1 byte
Uint8Array 0 至 255 1 octet
Uint8ClampedArray 0 至 255 1 octet
Int16Array -32768 至 32767 2 short
Uint16Array 0 至 65535 2 unsigned short
Int32Array -2147483648 至 2147483647 4 long
Uint32Array 0 至 4294967295 4 unsigned long
Float32Array -3.4e383.4e38 4 unrestricted float
Float64Array -1.8e3081.8e308 8 unrestricted double
BigInt64Array -263 至 263 - 1 8 bigint
BigUint64Array 0 到 264 - 1 8 bigint

值编码和标准化

¥Value encoding and normalization

所有类型化数组都在 ArrayBuffer 上运行,你可以在其中观察每个元素的确切字节表示形式,因此如何将数字编码为二进制格式非常重要。

¥All typed arrays operate on ArrayBuffers, where you can observe the exact byte representation of each element, so how the numbers are encoded in binary format is significant.

  • 无符号整数数组(Uint8ArrayUint16ArrayUint32ArrayBigUint64Array)直接以二进制形式存储数字。
  • 有符号整数数组(Int8ArrayInt16ArrayInt32ArrayBigInt64Array)使用 二进制补码 存储数字。
  • 浮点数组(Float32ArrayFloat64Array)使用 IEEE 754 浮点格式存储数字。Number 参考包含有关确切格式的更多信息。JavaScript 数字默认使用双精度浮点格式,与 Float64Array 相同。Float32Array 使用 23 位(而不是 52 位)作为尾数,使用 8 位(而不是 11 位)作为指数。请注意,规范要求所有 NaN 值使用相同的位编码,但确切的位模式取决于实现。
  • Uint8ClampedArray 是一个特例。它像 Uint8Array 一样以二进制形式存储数字,但是当你存储超出范围的数字时,它会通过数学值将数字限制在 0 到 255 的范围内,而不是截断最高有效位。

Int8ArrayUint8ArrayUint8ClampedArray 之外的所有类型化数组都使用多个字节存储每个元素。这些字节可以从最高有效到最低有效(大端)或从最低有效到最高有效(小端)排序。请参阅 字节顺序 了解更多说明。类型化数组始终使用平台的原生字节顺序。如果要在写入和读取缓冲区时指定字节顺序,则应使用 DataView

¥All typed arrays except Int8Array, Uint8Array, and Uint8ClampedArray store each element using multiple bytes. These bytes can either be ordered from most significant to least significant (big-endian) or from least significant to most significant (little-endian). See Endianness for more explanation. Typed arrays always use the platform's native byte order. If you want to specify the endianness when writing and reading from buffers, you should use a DataView instead.

当写入这些类型化数组时,超出可表示范围的值将被标准化。

¥When writing to these typed arrays, values that are outside the representable range are normalized.

  • 所有整数数组(Uint8ClampedArray 除外)都使用 固定宽度数字转换,它首先截断数字的小数部分,然后取最低位。
  • Uint8ClampedArray 首先将数字限制在 0 到 255 的范围内(大于 255 的值变为 255,小于 0 的值变为 0)。然后,它将结果四舍五入(而不是取整)到最接近的整数,半到偶数;这意味着如果数字正好位于两个整数之间,则会四舍五入到最接近的偶数。例如,0.5 变为 01.5 变为 22.5 变为 2
  • Float32Array 执行 "四舍五入到偶数" 将 64 位浮点数转换为 32 位。这与 Math.fround() 提供的算法相同。

查看可调整大小的缓冲区时的行为

¥Behavior when viewing a resizable buffer

TypedArray 作为 可调整大小的缓冲区 的视图创建时,调整底层缓冲区的大小将对 TypedArray 的大小产生不同的影响,具体取决于 TypedArray 是否构造为长度跟踪。

¥When a TypedArray is created as a view of a resizable buffer, resizing the underlying buffer will have different effects on the size of the TypedArray depending on whether the TypedArray is constructed as length-tracking.

如果通过省略第三个参数或传递 undefined 创建没有特定大小的类型化数组,则类型化数组将成为长度跟踪,并且会在调整后者大小时自动调整大小以适合基础 buffer

¥If a typed array is created without a specific size by omitting the third parameter or passing undefined, the typed array will become length-tracking, and will automatically resize to fit the underlying buffer as the latter is resized:

js
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

¥If a typed array is created with a specific size using the third length parameter, it won't resize to contain the buffer as the latter is grown:

js
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。这是非长度跟踪类型化数组的长度可能改变的唯一情况。

¥When a buffer is shrunk, the viewing typed array may become out of bounds, in which case the typed array's observed size will decrease to 0. This is the only case where a non-length-tracking typed array's length may change.

js
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 以使类型化数组回到边界内,则类型化数组的大小将恢复为其原始值。

¥If you then grow the buffer again to bring the typed array back in bounds, the typed array's size will be restored to its original value.

js
buffer.resize(8);

console.log(float32.byteLength); // 8
console.log(float32.length); // 2
console.log(float32[0]); // 0 - back in bounds again!

如果缓冲区缩小到 byteOffset 之外,长度跟踪类型数组也会发生同样的情况。

¥The same can happen for length-tracking typed arrays as well, if the buffer is shrunk beyond the byteOffset.

js
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

构造函数

¥Constructor

该对象无法直接实例化 - 尝试使用 new 构造它会抛出 TypeError

¥This object cannot be instantiated directly — attempting to construct it with new throws a TypeError.

js
new (Object.getPrototypeOf(Int8Array))();
// TypeError: Abstract class TypedArray not directly constructable

相反,你创建特定类型的类型化数组的实例,例如 Int8ArrayBigInt64Array。这些对象的构造函数都有一个通用的语法:

¥Instead, you create an instance of a typed array of a particular type, such as an Int8Array or a BigInt64Array. These objects all have a common syntax for their constructors:

js
new TypedArray()
new TypedArray(length)
new TypedArray(typedArray)
new TypedArray(object)

new TypedArray(buffer)
new TypedArray(buffer, byteOffset)
new TypedArray(buffer, byteOffset, length)

其中 TypedArray 是具体类型之一的构造函数。

¥Where TypedArray is a constructor for one of the concrete types.

注意:所有 TypedArray 子类的构造函数只能用 new 构造。尝试在没有 new 的情况下调用一个会抛出 TypeError

¥Note: All TypedArray subclasses' constructors can only be constructed with new. Attempting to call one without new throws a TypeError.

参数

¥Parameters

typedArray

当使用 TypedArray 子类的实例调用时,typedArray 被复制到新的类型化数组中。对于非 bigint TypedArray 构造函数,typedArray 参数只能是非 bigint 类型之一(例如 Int32Array)。同样,对于 bigint TypedArray 构造函数(BigInt64ArrayBigUint64Array),typedArray 参数只能是 bigint 类型之一。typedArray 中的每个值在复制到新数组之前都会转换为构造函数的相应类型。新类型化数组的长度将与 typedArray 参数的长度相同。

object

当使用不是 TypedArray 实例的对象调用时,将以与 TypedArray.from() 方法相同的方式创建一个新的类型化数组。

length Optional

当使用非对象调用时,参数将被视为指定类型化数组长度的数字。在内存中创建一个内部数组缓冲区,大小为 length 乘以 BYTES_PER_ELEMENT 字节,并用零填充。省略所有参数相当于使用 0 作为 length

buffer, byteOffset Optional, length Optional

当使用 ArrayBufferSharedArrayBuffer 实例以及可选的 byteOffsetlength 参数调用时,将创建一个新的类型化数组视图来查看指定的缓冲区。byteOffset(以字节为单位)和 length(以元素数量为单位,每个占用 BYTES_PER_ELEMENT 字节)参数指定类型化数组视图将公开的内存范围。如果两者都省略,则查看全部 buffer;如果仅省略 length,则查看从 byteOffset 开始的 buffer 的剩余部分。如果省略 length,类型化数组将变为 length-tracking

例外情况

¥Exceptions

所有 TypeArray 子类构造函数都以相同的方式操作。他们都会抛出以下异常:

¥All TypeArray subclass constructors operate in the same way. They would all throw the following exceptions:

TypeError

有下列情况之一的,抛出:

  • 传递了 typedArray,但它是 bigint 类型,而当前构造函数不是,反之亦然。
  • 传递了 typedArray,但它正在查看的缓冲区已分离,或者直接传递了分离的 buffer
RangeError

有下列情况之一的,抛出:

  • 新类型化数组的长度太大。
  • buffer(如果未指定 length 参数)或 byteOffset 的长度不是新类型化数组元素大小的整数倍。
  • byteOffset 不是有效的数组索引(0 到 253 - 1 之间的整数)。
  • 从缓冲区创建视图时,边界位于缓冲区之外。换句话说,byteOffset + length * TypedArray.BYTES_PER_ELEMENT > buffer.byteLength

静态属性

¥Static properties

这些属性在 TypedArray 构造函数对象上定义,因此由所有 TypedArray 子类构造函数共享。

¥These properties are defined on the TypedArray constructor object and are thus shared by all TypedArray subclass constructors.

TypedArray[@@species]

用于创建派生对象的构造函数。

所有 TypedArray 子类还具有以下静态属性:

¥All TypedArray subclasses also have the following static properties:

TypedArray.BYTES_PER_ELEMENT

返回不同 TypedArray 对象的元素大小的数值。

静态方法

¥Static methods

这些方法在 TypedArray 构造函数对象上定义,因此由所有 TypedArray 子类构造函数共享。

¥These methods are defined on the TypedArray constructor object and are thus shared by all TypedArray subclass constructors.

TypedArray.from()

从类似数组或可迭代的对象创建一个新的 TypedArray。另见 Array.from()

TypedArray.of()

创建一个具有可变数量参数的新 TypedArray。另见 Array.of()

实例属性

¥Instance properties

这些属性在 TypedArray.prototype 上定义并由所有 TypedArray 子类实例共享。

¥These properties are defined on TypedArray.prototype and shared by all TypedArray subclass instances.

TypedArray.prototype.buffer

返回类型化数组引用的 ArrayBuffer

TypedArray.prototype.byteLength

返回类型化数组的长度(以字节为单位)。

TypedArray.prototype.byteOffset

返回类型化数组相对于 ArrayBuffer 开头的偏移量(以字节为单位)。

TypedArray.prototype.constructor

创建实例对象的构造函数。TypedArray.prototype.constructor 是隐藏的 TypedArray 构造函数,但每个类型化数组子类还定义了自己的 constructor 属性。

TypedArray.prototype.length

返回类型化数组中保存的元素数。

TypedArray.prototype[@@toStringTag]

TypedArray.prototype[@@toStringTag] 属性的初始值是一个 getter,它返回与类型化数组构造函数的名称相同的字符串。如果 this 值不是类型化数组子类之一,则返回 undefined。该属性在 Object.prototype.toString() 中使用。但是,由于 TypedArray 也有自己的 toString() 方法,因此除非你使用类型化数组作为 thisArg 调用 Object.prototype.toString.call(),否则不会使用此属性。

所有 TypedArray 子类还具有以下实例属性:

¥All TypedArray subclasses also have the following instance properties:

TypedArray.prototype.BYTES_PER_ELEMENT

返回不同 TypedArray 对象的元素大小的数值。

实例方法

¥Instance methods

这些方法在 TypedArray 原型对象上定义,因此由所有 TypedArray 子类实例共享。

¥These methods are defined on the TypedArray prototype object and are thus shared by all TypedArray subclass instances.

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()

确定类型化数组是否包含某个元素,根据情况返回 truefalse。另见 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[@@iterator]()

返回一个新的数组迭代器对象,其中包含数组中每个索引的值。

示例

¥Examples

属性使用权

¥Property access

你可以使用标准数组索引语法(即使用括号表示法)引用数组中的元素。但是,在类型化数组上获取或设置索引属性不会在原型链中搜索该属性,即使索引超出范围也是如此。索引属性将参考 ArrayBuffer 并且永远不会查看对象属性。你仍然可以使用命名属性,就像使用所有对象一样。

¥You can reference elements in the array using standard array index syntax (that is, using bracket notation). However, getting or setting indexed properties on typed arrays will not search in the prototype chain for this property, even when the indices are out of bound. Indexed properties will consult the ArrayBuffer and will never look at object properties. You can still use named properties, just like with all objects.

js
// 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"

无法冷冻

¥Cannot be frozen

非空的 TypedArray 不能被冻结,因为它们的底层 ArrayBuffer 可能会通过缓冲区的另一个 TypedArray 视图发生突变。这意味着该对象永远不会真正被冻结。

¥TypedArrays that aren't empty cannot be frozen, as their underlying ArrayBuffer could be mutated through another TypedArray view of the buffer. This would mean that the object would never genuinely be frozen.

js
const i8 = Int8Array.of(1, 2, 3);
Object.freeze(i8);
// TypeError: Cannot freeze array buffer views with elements

ByteOffset 必须对齐

¥ByteOffset must be aligned

TypedArray 构造为 ArrayBuffer 的视图时,byteOffset 参数必须与其元素大小对齐;换句话说,偏移量必须是 BYTES_PER_ELEMENT 的倍数。

¥When constructing a TypedArray as a view onto an ArrayBuffer, the byteOffset argument must be aligned to its element size; in other words, the offset must be a multiple of BYTES_PER_ELEMENT.

js
const i32 = new Int32Array(new ArrayBuffer(4), 1);
// RangeError: start offset of Int32Array should be a multiple of 4
js
const i32 = new Int32Array(new ArrayBuffer(4), 0);

字节长度必须对齐

¥ByteLength must be aligned

byteOffset 参数一样,传递给 TypedArray 构造函数的 ArrayBufferbyteLength 属性必须是构造函数的 BYTES_PER_ELEMENT 的倍数。

¥Like the byteOffset parameter, the byteLength property of an ArrayBuffer passed to a TypedArray's constructor must be a multiple of the constructor's BYTES_PER_ELEMENT.

js
const i32 = new Int32Array(new ArrayBuffer(3));
// RangeError: byte length of Int32Array should be a multiple of 4
js
const i32 = new Int32Array(new ArrayBuffer(4));

规范

Specification
ECMAScript Language Specification
# sec-typedarray-objects

¥Specifications

浏览器兼容性

BCD tables only load in the browser

¥Browser compatibility

也可以看看