文章目录
简介
所谓类型化数组就是一种类似数组的对象,它提供了一种用于访问原始二进制数据的机制,WebGL
中经常会用到,并且必须用到,但这并不是说它的出现只是因为WebGL
,随着Web程序的越来强大,类型化数组还可以用在很多地方,让开发者可以方便的操作内存
首先来看下为什么会有类型化数组这个东西,JS已经有了Array对象为什么还有搞出来这样一个麻烦的东西,存在既有其合理性
- 浏览器通过
WebGL
与显卡进行通信,因此对性能要求较高,传统的Array动态数组无法满足 - 传统的Array可以存储任何类型的值,因此无法直接操作内存确定数据所占字节大小
- 有一些程序数据的交互通过二进制数据会更加快速,比如上面的显卡通信以及
webSockets
等
缓冲
何为缓冲
首先,需要了解以下什么是缓冲区
缓冲区又称为缓存,它是内存空间的一部分,也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,缓冲区根据其对应的设备是输入还是输出,又分为输入缓冲区和输出缓冲区。
例如在C语言中的内存管理机制,有两个标准的内存管理函数:malloc()
和free()
,用来申请固定大小的内存和动态释放内存空间,而在JavaScript中内存的管理是由浏览器来控制的,当创建变量时内存会被分配,使用变量时内存会被读写,然后当这些变量不再使用的时候内存会被回收,这就是JavaScript的垃圾自动回收机制。
缓冲的作用
然后,看下为什么需要缓冲区
了解了缓冲区是内存空间的一部分,它等待着数据的存取,那为什么不直接进行数据的存取还费那么大劲申请一块缓冲区再存取数据,因为缓冲区相当于一种媒介,介于输入和输出之间,就比如自动售货机,你买东西不需要要直接面对商家,即方便了你也方便了商家,并且你可以在售货机买到各种类型的东西,因此缓冲区它不是一种数据类型,在缓冲区这段内存区域中,可以放置整型数和浮点数以及别的类型
因此,JavaScript提供了一种可以缓冲区的类型,Arraybuffer
,当然这里的类型并不是类型化数组
ArrayBuffer
为了达到最大的灵活性和效率,类型数组将实现拆分为 缓冲和 视图两部分,一个缓冲描述的是一个数据块,缓冲没有格式可言,并且不提供机制访问内容
接口定义
ArrayBuffer
是一种数据类型,用来表示一个通用的、固定长度的二进制数据缓冲区,下面的代码是其接口定义
interface ArrayBuffer {
/**
* Read-only. The length of the ArrayBuffer (in bytes).
*/
readonly byteLength: number;
/**
* Returns a section of an ArrayBuffer.
*/
slice(begin: number, end?: number): ArrayBuffer;
}
由此可见ArrayBuffer
接口有一个只读属性和一个实例方法
byteLength
:数组的字节大小。在数组创建时确定,并且不可变更。只读。slice
:返回一个新的ArrayBuffer
,它的内容是这个ArrayBuffer
的字节副本,从begin(包括),到end(不包括)。如果begin或end是负数,则指的是从数组末尾开始的索引,而不是从头开始
静态方法
ArrayBuffer
还有一个静态的方法,其构造函数定义如下
interface ArrayBufferConstructor {
readonly prototype: ArrayBuffer;
new(byteLength: number): ArrayBuffer;
isView(arg: any): arg is ArrayBufferView;
}
isView
:如果参数是ArrayBuffer
的视图实例则返回true
,否则返回false
,至于什么是视图实例后面会讲解
下面来使用一下ArrayBuffer
// 创建8个字节的缓冲区
let buffer = new ArrayBuffer(8);
console.log(buffer.byteLength); // 返回字节长度8
let buffer2 = buffer.slice(0, 4);
console.log(buffer2.byteLength); // 4个字节数
上面创建一个8字节的内存缓冲区,并且通过byteLength
获取字节长度
每个字节的默认值都是0,1字节等于8比特,1比特就是一个二进制位(0或1)
DataView
上面创建了一个8字节的二进制缓冲区域,要想操作这块区域,ArrayBuffers不能直接读写,但可以将其传递给一个 类型化数组 TypedArray或DataView对象,进而操作缓冲区
首先,我们来看一下 DataView
DataVIew
是一个可以从 二进制ArrayBuffer 对象中读写多种数值类型的底层接口,使用它时,不用考虑不同平台的字节序 的问题。
接口定义
看一下其接口定义
interface DataView {
readonly buffer: ArrayBuffer;
readonly byteLength: number;
readonly byteOffset: number;
getFloat32(byteOffset: number, littleEndian?: boolean): number;
getFloat64(byteOffset: number, littleEndian?: boolean): number;
getInt8(byteOffset: number): number;
getInt16(byteOffset: number, littleEndian?: boolean): number;
getInt32(byteOffset: number, littleEndian?: boolean): number;
getUint8(byteOffset: number): number;
getUint16(byteOffset: number, littleEndian?: boolean): number;
getUint32(byteOffset: number, littleEndian?: boolean): number;
setFloat32(byteOffset: number, value: number, littleEndian?: boolean): void;
setFloat64(byteOffset: number, value: number, littleEndian?: boolean): void;
setInt8(byteOffset: number, value: number): void;
setInt16(byteOffset: number, value: number, littleEndian?: boolean): void;
setInt32(byteOffset: number, value: number, littleEndian?: boolean): void;
setUint8(byteOffset: number, value: number): void;
setUint16(byteOffset: number, value: number, littleEndian?: boolean): void;
setUint32(byteOffset: number, value: number, littleEndian?: boolean): void;
}
实例属性
实例属性
- buffer:类型是 ArrayBuffer,也就是被view引入的buffer只读属性
- byteLength:从 ArrayBuffer中读取的字节长度
- byteOffset:从 ArrayBuffer读取时的偏移字节长度
实例方法
实例方法
各个类型的set/get方法,表示从DataView起始位置以byte为计数的指定偏移量(byteOffset)处获取一个多少-bit数(类型).具体的类型和字节数如下表
视图类型 | 说明 | 字节大小 |
---|---|---|
Uint8Array | 8位无符号整数 | 1字节 |
Int8Array | 8位有符号整数 | 1字节 |
Uint8ClampedArray | 8位无符号整数(溢出处理不同) | 1字节 |
Uint16Array | 16位无符号整数 | 2字节 |
Int16Array | 16位有符号整数 | 2字节 |
Uint32Array | 32位无符号整数 | 4字节 |
Int32Array | 32位有符号整数 | 4字节 |
Float32Array | 32位IEEE浮点数 | 4字节 |
Float64Array | 64位IEEE浮点数 | 8字节 |
然后再看一下如果创建view对象,其构造函数定义如下
interface DataViewConstructor {
new(buffer: ArrayBufferLike, byteOffset?: number, byteLength?: number): DataView;
}
需要传递三个参数,后面两个是可选参数,参数详解
- buffer:一个 已经创建的ArrayBuffer也就是DataVIew的数据源
- byteOffset:此 DataView 对象的第一个字节在 buffer 中的字节偏移。如果未指定,则默认从第一个字节开始
- byteLength:此 DataView 对象的字节长度。如果未指定,这个视图的长度将匹配buffer的长度
代码示例
具体如果使用 DataView来看一下示例代码
// 创建8个字节的缓冲区
let buffer = new ArrayBuffer(8);
// 创建一个视图,从第一个字节开始到buffer的长度为止,通过视图可以操作缓冲区
let view = new DataView(buffer);
view.setUint8(0, 31