上一节阐述了如何声明 ArrayBuffer。而且其声明时的数值均为 0。
但在二进制的世界中,如何看待二进制的字节数,其结果是不同的。
譬如,长度为 8 的一串二进制 01010101 可以看做以下几种结果:
0、1、0、1、0、1、0、101、01、01、010101、010101010101
所以在这种情况下,我们能理解到的是:
ArrayBuffer二进制集合本身数据是没有意义的,除非提供了规则解释器。
这里的规则解释器,也称作视图。
视图对象本身并不存储任何东西。它是一副眼镜,透过它来解释存储在 ArrayBuffer 中的字节。
视图有两种:
TypedArray类型化数组。DataView数据视图。
TIP
在计算机中,一些信息可以用 1 个字节表示,可以用 2 个字节表示,甚至可以用 4 个字节表示。
也就是说二进制数据本身的含义在不同的规则(视图)下,其表示的含义是不同的。
所以这就是为什么 ArrayBuffer 只有在特定视图才有意义。
1.TypedArray
在 JavaScript 中并不存在名为 TypedArray 的构造函数。
这里的 TypedArray 是一类构造函数的总称:
Uint8Array: 8 位无符号整数。将每个字节视为0到255之间的单个数字(每个字节是8位,因此只能容纳那么多)。Uint16Array: 16 位无符号整数。将每2个字节视为一个0到65535之间的整数。Uint32Array: 32 位无符号整数将每4个字节视为一个 0 到 4294967295 之间的整数。Uint8ClampedArray: 用于8位整数,在赋值时便固定其值。Int8Array: 8 位无符号整数。Int16Array: 16 位无符号整数。Int32Array: 32 位无符号整数。Float32Array: 32 位有符号浮点数。Float64Array: 64 位有符号浮点数。
TIP
这些类型化数组的行为类似于常规数组:具有索引,并且是可迭代的。
本文中的 new TypedArray,它表示 new Uint8Array、new Int8Array 及其他中之一。
1-1.语法
TypedArray 的使用方法有以下五种:
// 1.以arrayBuffer为基础创建类型化数组 可以根据可选参数设置偏移量和指定长度
new TypedArray(arrayBuffer, [byteOffset], [length])
// 2.创建一个与目标数组相同长度的类型化数组,并复制其内容
new TypedArray(array)
// 3.类型数组之间互相转化
new TypedArray(typedArray)
// 4.创建指定长度的类型化数组
new TypedArray(length)
// 5.创建长度为零的类型化数组
new TypedArray()我们在此依次举例说明下前三种使用方式:
- 以
arrayBuffer为基础创建类型化数组,可以根据可选参数设置偏移量和指定长度。
var arrayBuffer = new ArrayBuffer(8)
var arr = new Uint16Array(arrayBuffer)
console.log(arr)这里我们声明了字节长度为 8 的 arrayBuffer,数值默认均为 0。
而后通过 16 位类型化数组视图(将两个字节视作一个数据)来描述它,最终视图数据长度为 4:

- 创建一个与目标数组相同长度的类型化数组,并复制其内容
var arr = new Uint16Array([72, 101, 108, 108, 111])
console.log(arr)
- 类型数组之间互相转化
var arr16 = new Uint16Array([254, 255, 256])
console.log(arr16)
var arr8 = new Uint8Array(arr16)
console.log(arr8)这里要说明的一个现象是,可能存在越界行为。
譬如,在 Uint8Array 下的数据范围 [0, 256),所以 256 在 Uint8Array 下转化时,数据会截取丢失。
即 100000000 被截取为 00000000,所以转化结果是 0。

TIP
Uint8ClampedArray 在这方面比较特殊,它的表现不太一样。
对于大于 255 的任何数字,它将保存为 255,对于任何负数,它将保存为 0。
此行为对于图像处理很有用。
1-2.方法
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方法(同样也支持),但不复制任何内容,只是创建一个新视图,以对给定片段的数据进行操作。
2.DataView
相比于类型化数组 TypedArray,DataView 的使用更加灵活。
对于类型化数组,构造器决定了其格式。整个数组应该是统一的。第 i 个数字是 arr[i]。
而通过 DataView,我们可以使用 getUint8(i) 或 getUint16(i) 之类的方法访问数据。
我们在调用方法时选择格式,而不是在构造的时候。
2-1.语法
其语法只有一种:
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当混合格式的数据存储在同一缓冲区(buffer)中时,DataView 非常有用。
例如,当我们存储一个成对序列(16 位整数,32 位浮点数)时,用 DataView 可以轻松访问它们。