js 的进制转换第二篇,Blob、File、ArrayBuffer、DataView、TypedArray。
上回说到,[js 中各个进制是怎么转换的](/home/进制(一) js的各种进制转换/),接下来看看,二进制在 js 中的实际使用和如何操作。
背景
实际开发的过程中,调用后端接口下载文件一般有两种方式 (以 axios 为例):
一是后端存储文件,生成文件地址,前端拿到地址后打开,如
1
2
3
4
5
6
7// 返回的 url 为文件地址 http://xxx.xxx.xlsx
axios.post(`${BASE_URL}/api`).then((res) => {
// open
window.open(res.url)
// location.href
location.href = res.url
})二是以二进制流的形式返回,此时响应头设置的 content-type 为 application/octet-stream:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24const downloadFile = (file, fileName = 'filename.xlsx') => {
// 如果 response type 为 blob
let blob = file
// 如果 response type 为 arraybuffer,转换为 Blob
if (file instanceof ArrayBuffer) {
blob = new Blob([file])
}
// 创建URL对象
const url = URL.createObjectURL(blob)
const el = document.createElement('a')
el.href = url
el.download = fileName
el.click()
// 释放URL对象
URL.revokeObjectURL(url)
}
// 返回二进制流
axios
.post(`${BASE_URL}/api`, {
responseType: 'blob', // 或者 arraybuffer
})
.then((res) => {
downloadFile(res)
})
这两种方式是很常用的
那什么是 Blob 和 ArrayBuffer 呢,与很少见到的 DataView、TypedArray,或者 常见的 File 有什么关系呢
解释
理了一下之间的关系,大致如下。

- Blob、File、ArrayBuffer 可以归为一类,它们都是数据或者说缓冲区;
- FileReader 算是一种工具,用来读取数据;
- DataView、TypedArray 是一种视图,视图对象本身并不存储任何东西。它是一副“眼镜”,透过它来解释存储在 ArrayBuffer 中的字节。
Blob
Blob (binary large object,二进制大文件对象)。表示一个不可变、原始数据的类文件对象。
只可以 slice 拆分,不能进行细粒度的操作,细粒度的操作需要转换成 ArrayBuffer。
创建:
1 | let blobObj = new Blob(array, options) |
属性:
1 | size:数据的字节大小(只读) |
操作方法:
1 | //start:分割起始点 |
File
File 就是文件,继承自 Blob,也是二进制对象。(可以用在任意的 Blob 类型的 context 中。比如说,FileReader 就能处理 Blob 和 File)。
有自己特有的属性和方法, 可以看到。
创建,类似于 Blob:
1 | // array:一堆数据构成的数组 |
常见属性:
1 | name:文件名 |
File 继承于 Blob,所以也拥有 slice 方法。
1 | new File([1], 'a.js').slice() |
ArrayBuffer
ArrayBuffer 是内存上一段二进制数据,我们可以借助工具 TypeArray、DataView 对它进行读写。
创建:
1 | let buffer = new ArrayBuffer(16) // 创建一个长度为 16 字节的 buffer |
区别:
- ArrayBuffer 是底层二进制数据,可以视图 TypeArray、DataView 进行读写。
- 而 Blob 是对底层二进制数据的封装,js 获取到的是一个整体,能够读取他的大小,类型,但是不能看到细节。
- Blob 作为一个整体文件,更适合用于传输;而只有需要关注细节(比如要修改某一段数据时),才需要用到 ArrayBuffer。
ArrayBuffer 转 Blob
1 | // 使用 new Blob 即可把 ArrayBuffer 的二进制数据进行封装 |
Blob 转 ArrayBuffer
1 | // ArrayBuffer() 可以将 blob 转换成 ArrayBuffer |
FileReader
FileReader
通过 fileReader 可以将 Blob、File 读取为不同的格式,常见:
- 将图片文件转换为 base64
1 | // FileReader.readAsDataURL(blob 将二进制数据读取并编码为 Base64 格式 |
TypedArray
TypedArray 没有直接的构造函数,常见的对他的实现有:
1 | // 下面代码是语法格式,不能直接运行, |
Uint8Array —— 将 ArrayBuffer 中的每个字节视为 0 到 255 之间的单个数字(00000000 ~ 11111111),称为 “8 位无符号整数”。
Uint16Array —— 将每 2 个字节视为一个 0 到 65535 之间的整数,称为 “16 位无符号整数”。
Uint32Array —— 将每 4 个字节视为一个 0 到 4294967295 之间的整数,称为 “32 位无符号整数”。
Float64Array —— 将每 8 个字节视为一个 5.0x10-324 到 1.8x10308 之间的浮点数。

因此,一个 16 字节 ArrayBuffer 中的二进制数据可以解释为:
- 16 个“小数字”
- 8 个更大的数字(每个数字 2 个字节)
- 4 个更大的数字(每个数字 4 个字节)
- 2 个高精度的浮点数(每个数字 8 个字节)。
实例:
1 | let arr = new Uint8Array([0, 1, 2, 3]) |
TypedArray 具有常规的 Array 方法,可以遍历(iterate),map,slice,find 和 reduce 等。
但没有 splice —— 无法“删除”一个值,因为类型化数组是缓冲区(buffer)上的视图,并且缓冲区(buffer)是固定的、连续的内存区域。我们所能做的就是分配一个零值。
也没有 concat 方法。