类型化数组、Blob 与 File
理解 ArrayBuffer、TypedArray 视图以及浏览器二进制文件对象。
类型数组详解
参考资料 ArrayBuffer,二进制数组
ArrayBuffer
❗ 提示
是基本的二进制对象, 对固定长度的连续内存空间的引用
创建
let buffer = new ArrayBuffer(16); // 创建一个长度为 16 的 buffer
alert(buffer.byteLength); // 16
// 它会分配一个 16 字节的连续内存空间,并用 0 进行预填充。
注意
❗ 提示
让我们先澄清一个可能的误区。
ArrayBuffer与Array没有任何共同之处:
- 它的长度是固定的,我们无法增加或减少它的长度。
- 它正好占用了内存中的那么多空间。
- 要访问单个字节,需要另一个“视图”对象,而不是
buffer[index]。
ArrayBuffer 是一个内存区域,它里面存储了一个原始的字节序列。
视图对象
视图对象的概念
❗ 提示
**“视图”对象 是操作
ArrayBuffer的工具,**本身并不存储任何东西,而是通过它的规则解释存储在ArrayBuffer中的字节,通用术语是 TypedArray
Uint8Array
将 ArrayBuffer 中的每个字节视为 0 到 255 之间的单个数字(每个字节是 8 位,因此只能容纳那么多)。这称为 “8 位无符号整数”。
Uint16Array
将每 2 个字节视为一个 0 到 65535 之间的整数。这称为 “16 位无符号整数”。
Uint32Array
将每 4 个字节视为一个 0 到 4294967295 之间的整数。这称为 “32 位无符号整数”。
Float64Array
将每 8 个字节视为一个 5.0x10(-324) 到 1.8x10(308) 之间的浮点数。

因此,一个 16 字节 ArrayBuffer 中的二进制数据可以解释为 16 个“小数字”,或 8 个更大的数字(每个数字 2 个字节),或 4 个更大的数字(每个数字 4 个字节),或 2 个高精度的浮点数(每个数字 8 个字节)
TypedArray属性和方法
创建方法
// 以上的几种类型数组,都有以下5中函数重载的实现,Uint32Array
new TypedArray(buffer, [byteOffset], [length]); // 除了提供buffer外,其他情况都会创建新的buffer
new TypedArray(object);
new TypedArray(typedArray);
new TypedArray(length);
new TypedArray();
属性
arr.buffer—— 引用ArrayBuffer。arr.byteLength——ArrayBuffer的长度
越界行为
对于越界值,会采用仅保留最右位,多余的位被切除的操作

Uint8``Clampe``dArray 在这方面比较特殊,它的表现不太一样。对于大于 255 的任何数字,它将保存为 255,对于任何负数,它将保存为 0。此行为对于图像处理很有用。
方法
TypedArray 具有常规的 Array 方法,但有个明显的例外。
我们可以遍历(iterate),map,slice,find 和 reduce 等。
但有几件事我们做不了:
- 没有
splice—— 我们无法“删除”一个值,因为类型化数组是缓冲区(buffer)上的视图,并且缓冲区(buffer)是固定的、连续的内存区域。我们所能做的就是分配一个零值。 - 无
concat方法。
还有两种其他方法:
arr.set(fromArr, [offset])从offset(默认为 0)开始,将fromArr中的所有元素复制到arr。arr.subarray([begin, end])创建一个从begin到end(不包括)相同类型的新视图。这类似于slice方法(同样也支持),但不复制任何内容 —— 只是创建一个新视图,以对给定片段的数据进行操作。
DataView`` 更灵活的TypedArray
DataView 是在 ArrayBuffer 上的一种特殊的超灵活“未类型化”视图。它允许以任何格式访问任何偏移量(offset)的数据。
- 对于类型化的数组,构造器决定了其格式。整个数组应该是统一的。第 i 个数字是
arr[i]。 - 通过
DataView,我们可以使用.getUint8(i)或.getUint16(i)之类的方法访问数据。我们在调用方法时选择格式,而不是在构造的时候。
语法:
new DataView(buffer, [byteOffset], [byteLength])
buffer—— 底层的ArrayBuffer。与类型化数组不同,DataView不会自行创建缓冲区(buffer)。我们需要事先准备好。byteOffset—— 视图的起始字节位置(默认为 0)。byteLength—— 视图的字节长度(默认至buffer的末尾)。
/ 4 个字节的二进制数组,每个都是最大值 255
let buffer = new Uint8Array([255, 255, 255, 255]).buffer;
let dataView = new DataView(buffer);
// 在偏移量为 0 处获取 8 位数字
alert( dataView.getUint8(0) ); // 255
// 现在在偏移量为 0 处获取 16 位数字,它由 2 个字节组成,一起解析为 65535
alert( dataView.getUint16(0) ); // 65535(最大的 16 位无符号整数)
// 在偏移量为 0 处获取 32 位数字
alert( dataView.getUint32(0) ); // 4294967295(最大的 32 位无符号整数)
dataView.setUint32(0, 0); // 将 4 个字节的数字设为 0,即将所有字节都设为 0
可以自由操作二进制数字了
Blob 和File
Blob
💡 提示
Blob对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成ReadableStream来用于数据操作
构造函数
blobParts可选一个可迭代对象,比如Array,包含ArrayBuffer、TypedArray、DataView、Blob、字符串或者任意这些元素的混合,这些元素将会被放入Blob中。options可选一个可以指定以下任意属性的对象:-
- 一个包含指定数据的新的
Blob对象。
- 一个包含指定数据的新的
实例属性、方法
实例属性
实例方法
Blob.arrayBuffer()返回一个 promise,其会兑现一个包含Blob所有内容的二进制格式的ArrayBuffer。Blob.slice()返回一个新的Blob对象,其中包含调用它的 blob 的指定字节范围内的数据。Blob.stream()返回一个能读取Blob内容的ReadableStream。Blob.text()返回一个 promise,其会兑现一个包含Blob所有内容的 UTF-8 格式的字符串。
const obj = { hello: "world" };
const blob = new Blob([JSON.stringify(obj, null, 2)], {
type: "application/json",
});
读取方式
从 Blob 对象中提取数据有几种不同的方法,每种方法都适用于不同的场景和数据类型。下面是 arrayBuffer()、FileReader、Blob.text() 和 Response(blob).text() 方法的区别:
Blob.arrayBuffer():- 这个方法返回一个
Promise,它解析为一个ArrayBuffer对象。 - 它适用于任何类型的 Blob 数据,不仅限于文本。
- 它不关心 Blob 的类型,只将数据作为原始二进制数据返回。
- 这个方法返回一个
FileReader:FileReader是一个更通用的接口,可以用来读取文件或 Blob 数据。- 它支持多种读取模式,例如
readAsText(),readAsDataURL(), 和readAsArrayBuffer()。 - 使用
FileReader时,你可以指定编码(仅当读取文本时)。 FileReader通常用于读取文件输入字段中的文件。
Blob.text():- 这个方法是
Blob对象的一个便利方法,返回一个Promise,解析为一个字符串。 - 它专门用于读取文本数据,自动将 Blob 中的数据解码为 UTF-8 字符串。
- 它适用于文本类型的 Blob,例如 JSON、XML 或纯文本。
- 这个方法是
Response(blob).text():- 这个方法是
Response对象的一个方法,用于从Response对象中提取文本数据。 - 当你从
fetchAPI 接收到一个包含 Blob 类型的响应时,可以使用Response.text()来获取响应体的文本表示。 - 它与
Blob.text()类似,但Response.text()可以处理来自网络请求的响应体。
- 这个方法是
总结来说,选择哪种方法取决于你需要处理的数据类型和上下文:
- 如果你需要处理二进制数据,使用
Blob.arrayBuffer()。 - 如果你需要读取文本数据,并且 Blob 类型已知,使用
Blob.text()或Response.text()。 - 如果你需要更多的灵活性,例如不同的编码或不同的读取模式,使用
FileReader。
File
继承自Blob,是它的一个扩展