二进制数组
ArrayBuffer
对象、TypedArray
视图和DataView
视图是 JavaScript 以数组的语法操作二进制数据接口,也叫二进制数组;这些接口设计的初衷是为了满足浏览器与显卡通信时大量实时的数据交换二进制数组并非真正的数组,而是类数组对象
ES6 将二进制数组纳入规范,并增加了新的方法
视图
JavaScript 类型数组(
Typed Arrays
)将实现拆分为缓冲和视图两部分。一个缓冲(由ArrayBuffer
对象实现)描述的是一个数据块。缓冲没有格式且不提供机制访问其内容;为了访问缓冲对象中包含的内存,需要使用视图;视图提供了上下文 — 即数据类型、起始偏移量和元素数 — 将数据转换为实际有类型的数组
类型数组包含两种视图,一种是
TypedArray
视图,另一种是DataView
视图;前者的数组成员都是同一个数据类型,后者的数组成员可以是不同的数据类型
ArrayBuffer
ArrayBuffer
是一种数据类型,用来表示一个通用的、固定长度的二进制数据缓冲区;这段缓冲区内容无法直接读写,只能通过TypedArray
或DataView
以指定格式解读这段二进制数据
ArrayBuffer
也是构造函数,可以分配一段存储数据的连续内存区域;构造函数的参数代表的是所需内存大小(单位为字节),每个字节默认值均为 0
1 | const buffer = new ArrayBuffer(32); |
方法和属性
byteLength
返回所分配的内存区域的字节长度
需要检查是否分配成功;如果待分配的内存区域过大,有可能分配失败(没有足够多的连续空余内存)
1
2
3
4
5
6
7
8const buffer = new ArrayBuffer(32);
buffer.byteLength; // 32
if (buffer.byteLength === n) {
// 分配成功
} else {
// 分配失败
}slice()
截取原
ArrayBuffer
对象,生成一份新的ArrayBuffer
对象该方法参数与数组
slice
一致,第一个参数指截取开始位置,第二个参数指的是截取结束位置(不包含)1
2const buffer = new ArrayBuffer(32);
const newBuffer = buffer.slice(0, 3);ArrayBuffer.isView()
此方法为
ArrayBuffer
静态方法,判断参数是否为TypedArray
或DataView
实例1
2
3
4
5const buffer = new ArrayBuffer(32);
ArrayBuffer.isView(buffer);
const v = new Int32Array(buffer);
ArrayBuffer.isView(v);
TypedArray
TypedArray
包括 9 种类型,每一种类型都是一种构造函数
类型 | 描述 | 取值范围 | 长度 |
---|---|---|---|
Int8Array | 8 位有符号整数 | -128 ~ 127 | 1 |
Uint8Array | 8 位无符号整数 | 0 ~ 255 | 1 |
Uint8ClampedArray | 8 位无符号整数(溢出处理不同) | 0 ~ 255 | 1 |
Int16Array | 16 位有符号整数 | -32768 ~ 32767 | 2 |
Uint16Array | 16 位无符号整数 | 0 ~ 65535 | 2 |
Int32Array | 32 位有符号整数 | -2147483638 ~ 213647483647 | 4 |
Uint32Array | 32 位无符号整数 | 0 ~ 4294967295 | 4 |
Float32Array | 32 位浮点数 | 1.2x10-38 ~ 3.4x1038 | 4 |
Float64Array | 64 位浮点数 | 5.0x10-324 ~ 1.8x10308 | 8 |
普通数组与 TypedArray 数组差异
- TypedArray 数组的所有成员都是同一种类型
- TypedArray 数组的成员是连续的
- TypedArray 数组成员的默认值为 0
- TypedArray 数组只是一层视图,本身不储存数据,数据都储存在底层
ArrayBuffer
对象之中 - TypedArray 数组包含的方法与普通数组基本一致,唯一特殊的是没有
concat
方法
构造函数
TypedArray
数组提供 9 种构造函数,用来生成相应类型的数组实例。
下面是构造函数的各种用法:
TypedArray(buffer, byteOffset=0, length?)
第一个参数为必需,指
ArrayBuffer
对象,后面两个参数分别是开始和结束位置,默认从 0 开始到最大长度根据同一
ArrayBuffer
对象创建多个TypedArray
时,对任何一个类型数组进行修改,都会影响其它类型数组,因为类型数组只是视图创建不同类型的类型数组时,
byteOffset
参数有相应的字节倍数限制,如:Int16Array 类型数组是 4 字节,因而byteOffset
只能为 4 的倍数1
2
3
4
5
6
7
8
9
10const buffer = new ArrayBuffer(8);
const buff_16 = new Uint16Array(buffer);
const buff_32 = new Int32Array(buffer);
buff_16[0] = 10;
buff_16[1] = 11;
console.log(buff_16);
console.log(buff_32);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16const buffer = new ArrayBuffer(8);
console.log(new Int8Array(buffer, 1)); // Int8Array { [Iterator] '0': 0, '1': 0, '2': 0, '3': 0, '4': 0, '5': 0, '6': 0 }
new Int16Array(buffer, 1); // start offset of Int16Array should be a multiple of 2
console.log(new Int16Array(buffer, 2)); // Int16Array { [Iterator] '0': 0, '1': 0, '2': 0 }
new Int32Array(buffer, 2); // start offset of Int32Array should be a multiple of 4
console.log(new Int32Array(buffer, 4)); // Int32Array { [Iterator] '0': 0 }
new Float32Array(buffer, 2); // start offset of Float32Array should be a multiple of 4
console.log(new Float32Array(buffer, 4)); // Float32Array { [Iterator] '0': 0 }
new Float64Array(buffer, 4); // start offset of Float64Array should be a multiple of 8
console.log(new Float64Array(buffer)); // Float64Array { [Iterator] '0': 0 }
console.log(new Float64Array(buffer, 8)); // Float64Array { [Iterator] }
TypedArray(length)
也可以不通过
ArrayBuffer
对象,直接分配内存长度,再进行赋值1
2
3
4
5
6const buff_8 = new Int8Array(8);
buff_8[0] = 1;
buff_8[1] = 2;
console.log(buff_8);TypedArray(typedArray)
还可以接受另外一个
TypedArray
实例作为参数,生成新的TypedArray
类型数组新生成的
TypedArray
数组只是复制了原数组的值,对应底层ArrayBuffer
不一样;新数组生成时也会创建新的ArrayBuffer
对象存储数据,不会在原数组的ArrayBuffer
对象上建立视图1
2
3
4
5
6
7
8const buff_8 = new Int8Array(2);
const buff8 = new Int8Array(buff_8);
buff_8[0] = 1;
buff8[0] = 2;
console.log(buff_8);
console.log(buff8);1
2
3
4
5
6
7
8
9// 基于同一 ArrayBuffer 建立视图
const buff_8 = new Int8Array([1, 2]);
const buff8 = new Int8Array(buff_8.buffer);
console.log(buff_8[0]);
console.log(buff8[0]);
buff_8[0] = 2;
console.log(buff8[0]);TypedArray(array)
构造函数的参数也可以是一个普通数组或类数组,然后直接生成
TypedArray
实例此时
TypedArray
视图不会在原数组的内存上建立视图,会重新创建ArrayBuffer
对象1
2
3
4
5const buff_8 = new Int8Array([1, 2, 3]);
console.log(buff_8);
const buff_16 = new Int16Array({ length: 2, 0: 0, 1: 2});
console.log(buff_16);