| 类 | 描述 |
|---|---|
TypedArray | 一族类,提供类似 Array 的接口来操作二进制数据。包括 Uint8Array、Uint16Array、Int8Array 等。 |
Buffer | Uint8Array 的子类,实现了一系列便捷方法。与本表中的其他元素不同,这是一个 Node.js API(Bun 实现了它)。不能在浏览器中使用。 |
DataView | 一个类,提供 get/set API,用于在 ArrayBuffer 的特定字节偏移处写入一定数量的字节。通常用于读取或写入二进制协议。 |
Blob | 表示文件的只读二进制数据块。具有 MIME type、size,以及转换为 ArrayBuffer、ReadableStream 和字符串的方法。 |
File | Blob 的子类,表示一个文件。具有 name 和 lastModified 时间戳。在 Node.js v20 中有实验性支持。 |
BunFile | 仅 Bun。Blob 的子类,表示磁盘上的延迟加载文件。通过 Bun.file(path) 创建。 |
ArrayBuffer 和视图
直到 2009 年,JavaScript 中没有语言原生的方式来存储和操作二进制数据。ECMAScript v5 引入了一系列新机制来解决这个问题。最基本的构建块是 ArrayBuffer,这是一个简单的数据结构,表示内存中的字节序列。
ArrayBuffer 读取或写入值。除了检查其大小并从中创建”切片”之外,几乎没什么可做的。
ArrayBuffer 实例并允许您读取和操作底层数据。有两种类型的视图:_类型化数组_和 DataView。
DataView
DataView 类是用于读取和操作 ArrayBuffer 中数据的低级接口。
下面我们创建一个新的 DataView 并将第一个字节设置为 3。
1 处写入一个 Uint16。这需要两个字节。我们使用值 513,即 2 * 256 + 1;以字节表示,那就是 00000010 00000001。
ArrayBuffer 的前三个字节中分配了一个值。即使第二和第三字节是使用 setUint16() 创建的,我们仍然可以使用 getUint8() 读取其各个字节。
ArrayBuffer 中可用空间更多的值会导致错误。下面我们尝试在字节偏移量 0 处写入一个 Float64(需要 8 个字节),但缓冲区中总共只有四个字节。
DataView 上使用:
TypedArray
类型化数组是一族类,提供类似 Array 的接口来操作 ArrayBuffer 中的数据。与 DataView 允许您在特定偏移量处写入不同大小的数字不同,TypedArray 将底层字节解释为数字数组,每个数字具有固定大小。
通常通过它们的共享超类
TypedArray 来指代这一族类。这个类在 JavaScript 中是内部的;
您无法直接创建其实例,而且 TypedArray 在全局作用域中未定义。
可以将其视为 interface 或抽象类。ArrayBuffer 是一个通用的字节序列,但这些类型化数组类将字节解释为给定字节大小的数字数组。
第一行包含原始字节,后面的行包含当使用不同类型化数组类_查看_时这些字节将如何解释。
以下是类型化数组类,以及它们如何解释 ArrayBuffer 中的字节的描述:
以下是第一个表格的 Markdown 格式:
| 类 | 描述 |
|---|---|
Uint8Array | 每个一个(1)字节被解释为无符号 8 位整数。范围 0 到 255。 |
Uint16Array | 每两个(2)字节被解释为无符号 16 位整数。范围 0 到 65535。 |
Uint32Array | 每四个(4)字节被解释为无符号 32 位整数。范围 0 到 4294967295。 |
Int8Array | 每个一个(1)字节被解释为有符号 8 位整数。范围 -128 到 127。 |
Int16Array | 每两个(2)字节被解释为有符号 16 位整数。范围 -32768 到 32767。 |
Int32Array | 每四个(4)字节被解释为有符号 32 位整数。范围 -2147483648 到 2147483647。 |
Float16Array | 每两个(2)字节被解释为 16 位浮点数。范围 -6.104e5 到 6.55e4。 |
Float32Array | 每四个(4)字节被解释为 32 位浮点数。范围 -3.4e38 到 3.4e38。 |
Float64Array | 每八个(8)字节被解释为 64 位浮点数。范围 -1.7e308 到 1.7e308。 |
BigInt64Array | 每八个(8)字节被解释为有符号 BigInt。范围 -9223372036854775808 到 9223372036854775807(虽然 BigInt 能够表示更大的数字)。 |
BigUint64Array | 每八个(8)字节被解释为无符号 BigInt。范围 0 到 18446744073709551615(虽然 BigInt 能够表示更大的数字)。 |
Uint8ClampedArray | 与 Uint8Array 相同,但在向元素分配值时自动”限制”到 0-255 范围。 |
ArrayBuffer 中的字节是如何解释的。
| 字节 0 | 字节 1 | 字节 2 | 字节 3 | 字节 4 | 字节 5 | 字节 6 | 字节 7 | |
|---|---|---|---|---|---|---|---|---|
ArrayBuffer | 00000000 | 00000001 | 00000010 | 00000011 | 00000100 | 00000101 | 00000110 | 00000111 |
Uint8Array | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
Uint16Array | 256 (1 * 256 + 0) | 770 (3 * 256 + 2) | 1284 (5 * 256 + 4) | 1798 (7 * 256 + 6) | ||||
Uint32Array | 50462976 | 117835012 | ||||||
BigUint64Array | 506097522914230528n |
ArrayBuffer 创建类型化数组:
ArrayBuffer 实例化一个 Uint32Array,我们会得到一个错误。
Uint32 值需要四个字节(32 位)。由于 ArrayBuffer 长 10 字节,无法干净地将其内容分成 4 字节块。
为了解决这个问题,我们可以创建一个 ArrayBuffer 特定”切片”上的类型化数组。下面的 Uint16Array 只”查看”底层 ArrayBuffer 的前 8 个字节。为实现这些,我们指定 byteOffset 为 0,length 为 2,这表示我们希望数组包含的 Uint32 数字的数量。
ArrayBuffer 实例;而是可以直接在类型化数组构造函数中指定长度:
push 和 pop 在类型化数组上不可用,因为它们需要调整底层 ArrayBuffer 的大小。
Uint8Array
特别值得一提 Uint8Array,因为它表示经典的”字节数组”-0 到 255 之间的 8 位无符号整数序列。这是您在 JavaScript 中遇到的最常见的类型化数组。
在 Bun 中,以及将来在其他 JavaScript 引擎中,它具有在字节数组和 base64 或十六进制字符串等序列化表示之间转换的方法。
TextEncoder#encode 的返回值,也是 TextDecoder#decode 的输入类型,这两个实用类设计用于转换字符串和各种二进制编码,最著名的是 "utf-8"。
Buffer
Bun 实现了 Buffer,这是一个用于处理二进制数据的 Node.js API,早于 JavaScript 规范中引入类型化数组。它后来被重新实现为 Uint8Array 的子类。它提供了一系列方法,包括多个类似数组和类似 DataView 的方法。
Blob
Blob 是一个 Web API,常用于表示文件。Blob 最初是在浏览器中实现的(不像 ArrayBuffer 是 JavaScript 本身的一部分),但现在在 Node 和 Bun 中得到了支持。
直接创建 Blob 实例并不常见。更多时候,您会从外部源(如浏览器中的 <input type="file"> 元素)或库接收 Blob 实例。也就是说,可以从一个或多个字符串或二进制”blob 部分”创建 Blob。
string、ArrayBuffer、TypedArray、DataView 或其他 Blob 实例。blob 部分按提供的顺序连接在一起。
Blob 的内容可以异步读取为各种格式。
BunFile
BunFile 是 Blob 的子类,用于表示磁盘上的延迟加载文件。像 File 一样,它添加了 name 和 lastModified 属性。与 File 不同,它不需要将文件加载到内存中。
File
File 是 Blob 的子类,添加了 name 和 lastModified 属性。它通常在浏览器中用于表示通过 <input type="file"> 元素上传的文件。Node.js 和 Bun 实现了 File。
流
流是一种重要的抽象,用于处理二进制数据,而无需将所有数据一次性加载到内存中。它们通常用于读写文件、发送和接收网络请求以及处理大量数据。 Bun 实现了 Web APIReadableStream 和 WritableStream。
要创建一个简单的可读流:
for await 语法逐块读取。
转换
从一种二进制格式转换为另一种格式是一项常见任务。本节旨在作为参考。从 ArrayBuffer
由于 ArrayBuffer 存储了其他二进制结构(如 TypedArray)所依赖的数据,下面的代码片段并不是真正从 ArrayBuffer_转换_为另一种格式。相反,它们是使用存储的底层数据_创建_新实例。
至 TypedArray
至 DataView
至 Buffer
至 string
作为 UTF-8:
至 number[]
至 Blob
至 ReadableStream
以下代码片段创建一个 ReadableStream 并将整个 ArrayBuffer 作为一个块排队。
分块
分块
要将
ArrayBuffer 分块流式传输,请使用 Uint8Array 视图并将每个块排队。从 TypedArray
至 ArrayBuffer
这将检索底层 ArrayBuffer。请注意,TypedArray 可能是底层缓冲区的_切片_视图,因此大小可能不同。
至 DataView
创建覆盖与 TypedArray 相同字节范围的 DataView。
至 Buffer
至 string
作为 UTF-8:
至 number[]
至 Blob
至 ReadableStream
分块
分块
要将
ArrayBuffer 分块流式传输,请将 TypedArray 分割成块并分别排队每个块。从 DataView
至 ArrayBuffer
至 TypedArray
仅当 DataView 的 byteLength 是 TypedArray 子类的 BYTES_PER_ELEMENT 的倍数时才有效。
至 Buffer
至 string
作为 UTF-8:
至 number[]
至 Blob
至 ReadableStream
分块
分块
要将
ArrayBuffer 分块流式传输,请将 DataView 分割成块并分别排队每个块。从 Buffer
至 ArrayBuffer
至 TypedArray
至 DataView
至 string
作为 UTF-8:
至 number[]
至 Blob
至 ReadableStream
分块
分块
要将
ArrayBuffer 分块流式传输,请将 Buffer 分割成块并分别排队每个块。从 Blob
至 ArrayBuffer
Blob 类为此目的提供了一个便捷方法。
至 TypedArray
至 DataView
至 Buffer
至 string
作为 UTF-8:
至 number[]
至 ReadableStream
从 ReadableStream
使用 Response 作为便捷的中间表示形式很常见,这样更容易将 ReadableStream 转换为其他格式。
ReadableStream 转换为各种二进制格式。
至 ArrayBuffer
至 Uint8Array
至 TypedArray
至 DataView
至 Buffer
至 string
作为 UTF-8:
至 number[]
ReadableStream 解析为其块的数组。每个块可能是字符串、类型化数组或 ArrayBuffer。
至 Blob
至 ReadableStream
要将 ReadableStream 分成两个可以独立消费的流: