二进制字段由三种类型的对象组成:
让我们仔细看看如何使用它们:
1.ArrayBuffer对象
不能直接读写,只能通过(TypedArray和DataView)读写。
ArrayBuffer也是一个构造函数,可以分配一块连续的可以存储数据的显存区域。
比如我要生成一个32字节的显存区域,每个字节的值默认都是0,那么我可以这样创建:
var buf = new ArrayBuffer(32);
ArrayBuffer.prototype.byteLength
byteLength:ArrayBuffer实例的属性,返回分配的显存区域的字节宽度。
var buffer = new ArrayBuffer(32);
buffer.byteLength // 32
需要注意的是,如果要分配比较大的显存区域,需要检查分配是否成功,因为可能没有那么多连续的空闲显存。
if(buffer.byteLength === n){
//成功
}else{
//失败
}
ArrayBuffer.prototype.slice()
slice:有两个参数,第一个参数表示开始复制的字节序号(包括本字节),第二个参数表示复制之前的字节序号(不包括本字节),如果第二个参数省略,则默认到原始 ArrayBuffer 对象的末尾。
slice:ArrayBuffer实例的一个方法,允许复制一部分显存区域,生成一个新的ArrayBuffer对象。
var buffer = new ArrayBuffer(8);
var newBuffer = buffer.slice(0, 3);
//拷贝`buffer`对象的前三个字节(从0到3前结束),生成一个新的ArrayBuffer对象:newBuffer
数组缓冲区。 isView()
isView:是ArrayBuffer的静态方法,返回一个布尔值,指示参数是否是ArrayBuffer的视图实例。 这个方法大致相当于判断参数是TypedArray实例还是DataView实例。
var buffer = new ArrayBuffer(8);
ArrayBuffer.isView(buffer) // false
var v = new Int32Array(buffer);
ArrayBuffer.isView(v) // true
2. TypedArray 视图
TypedArray链表只提供了9个固定的构造函数,用于生成对应类型的字段实例。
(1) TypedArray(缓冲区, byteOffset=0, 长度?)
视图的构造函数可以接受三个参数:
// 创建一个8字节的ArrayBuffer
var b = new ArrayBuffer(8);
// 创建一个指向b的Int32视图,开始于字节0,直到缓冲区的末尾
var v1 = new Int32Array(b);
// 创建一个指向b的Uint8视图,开始于字节2,直到缓冲区的末尾
var v2 = new Uint8Array(b, 2);
// 创建一个指向b的Int16视图,开始于字节2,长度为2
var v3 = new Int16Array(b, 2, 2);
v1[0]是一个32位整数,指向字节0~字节3; v2[0]是一个8位无符号整数,指向字节2; v3[0]是一个16位整数,指向字节2~字节3。只要任意一个视图对显存进行了更改,就会反映在另外两个视图中。
注意:byteOffset必须与要完善的数据类型一致,例如:有符号的16位整数需要两个字节,因此byteOffset参数必须能被2整除
(2) 类型化数组(长度)
视图也可以通过直接分配视频内存而不使用 ArrayBuffer 对象来生成。
var f64a = new Float64Array(8); //64字节
f64a[0] = 10;
f64a[1] = 20;
f64a[2] = f64a[0] + f64a[1]; // 30
(3) 类型数组(typedArray)
TypedArray 字段的构造函数,可以接受另一个 TypedArray 实例作为参数。
var typedArray = new Int8Array(new Uint8Array(4));
注意:新字段将开辟新的显存数据段。
var x = new Int8Array([1, 1]);
var y = new Int8Array(x);
x[0] // 1
y[0] // 1
x[0] = 2;
y[0] // 1
//基于同一段内存
var x = new Int8Array([1, 1]);
var y = new Int8Array(x.buffer);
x[0] // 1
y[0] // 1
x[0] = 2;
y[0] // 2
(4) TypedArray(arrayLikeObject)
//普通数组生成TypedArray实例
var typedArray = new Uint8Array([1, 2, 3, 4]);
//这时TypedArray视图会重新开辟内存,不会在原数组的内存上建立视图
//TypedArray数组转换回普通数组
var normalArray = Array.prototype.slice.call(typedArray);
需要注意的是ecmascript 6数组,TypedArray字段不仅没有concat方法,而且具有普通链表的所有操作方法和属性
如果你想合并多个TypedArray链表,可以使用下面的函数。
function concatenate(resultConstructor, ...arrays) {
let totalLength = 0;
for (let arr of arrays) {
totalLength += arr.length;
}
let result = new resultConstructor(totalLength);
let offset = 0;
for (let arr of arrays) {
result.set(arr, offset);
offset += arr.length;
}
return result;
}
concatenate(Uint8Array, Uint8Array.of(1, 2), Uint8Array.of(3, 4))
// Uint8Array [1, 2, 3, 4]
TypedArray 列表也可以被遍历。
let ui8 = Uint8Array.of(0, 1, 2);
for (let byte of ui8) {
console.log(byte);
}
// 0
// 1
// 2
ArrayBuffer 和 String 之间的转换
注意:字符串的编码方式是确定后才能相互转换的。
// ArrayBuffer转为字符串,参数为ArrayBuffer对象
function ab2str(buf) {
return String.fromCharCode.apply(null, new Uint16Array(buf));
}
// 字符串转为ArrayBuffer对象,参数为字符串
function str2ab(str) {
var buf = new ArrayBuffer(str.length * 2); // 每个字符占用2个字节
var bufView = new Uint16Array(buf);
for (var i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
TypedArray.prototype.buffer:返回整个显存区域对应的ArrayBuffer对象,属性只读。
TypedArray.prototype.byteLength:返回被TypedArray字段抢占的显存宽度,单位为字节,该属性是只读的。
TypedArray.prototype.byteOffset:返回的TypedArray链表从底层ArrayBuffer对象的字节开始,该属性是只读的。
TypedArray.prototype.length:TypedArray链表有多少个成员。
TypedArray.prototype.set():用于复制链表(普通链表或TypedArray链表)。
TypedArray.prototype.subarray():对于TypedArray链表的一部分,完成一个新的视图。
TypedArray.prototype.slice():在指定位置返回一个新的TypedArray实例。
TypedArray.of():用于将参数转换为TypedArray实例。
TypedArray.from():返回基于此结构的TypedArray实例。
3. 复合视图
var buffer = new ArrayBuffer(24);
var idView = new Uint32Array(buffer, 0, 1);
var usernameView = new Uint8Array(buffer, 4, 16);
var amountDueView = new Float32Array(buffer, 20, 1);
上面的代码将一个宽度为24字节的ArrayBuffer对象分为三部分:
4.DataView视图
DataView 实例具有以下属性ecmascript 6数组,这些属性与同名的 TypedArray 实例具有相同的含义。
DataView实例提供了8种读取显存的方法。
DataView 视图提供了 8 种写入视频内存的方法。