ES6 类型数组(JavaScript typed arrays)-JavaScript对二进制数据读写的实现

 2016年05月07日    378     声明


JavaScript类型数组(JavaScript typed arrays)是一种类似数组的对象,它由ArrayBufferTypedArrayDataView三类对象构成,通过这些对象为JavaScript提供了访问二进制数据的能力。


  1. 类型数组(二进制数组)
  2. ArrayBuffer对象
  3. TypedArray视图对象
  4. 4. DataView

1. 类型数组(二进制数组)

1.1 概述

在以往的Web应用中,JavaScript处理二进制数据,需要数据当作String并且使用charCodeAt()方法从数据缓冲区(buffer)中读取字节。在这种方式下,处理数据需要多次进行数据转换,不仅效率低而且容易出错。

随着Web应用变得日益强大,各种新功能,如:音/视频处理、通过WebSocket直接访问原始数据等。如果 JavaScript 能够快速而直接的处理原始数据这将会对我们很有帮助。

JavaScript typed arrays(类型数组)提供了一种更加高效的机制来访问和处理原始二进制数据。类型数组并不同于普通意义上的Array对象,在它上面调用Array.isArray()方法时会返回false


1.2 缓存(Buffer)与视图(View):typed array架构

为了达到最大的灵活性和高效性, JavaScript 的typed array把实现分成了缓存(Buffer)和视图(View)。缓存是ArrayBuffer类的实现),是一个表示某数据片段的对象,它本身并没有格式可言,要访问它的数据应该使用一个视图。 视图提供了一个数据类型,起始数据偏移量,和其他一些元素,通过这些把数据转化成实际的数组类型。

二进制数组由以下对象组成:

ArrayBuffer

ArrayBuffer是一个用于表示二进制缓冲区(buffer)的对象,它并没有能力去访问和操作它自身的数据内容,要操作 ArrayBuffer中的数据,需要创建一个Typed array viewsDataView来读写缓存区内容。

Typed array views

Typed array views是一组具有描述性的名字的不同类型的数组视图,如:Int8ArrayInt32ArrayFloat32Array等。

DataView

DataView 提供了一些底层的API,通过这些API可以从ArrayBuffer中读/写数据。


2. ArrayBuffer对象

ArrayBuffer是缓存数组对象,是一种用于呈现通用、固定长度的二进制数据的类型。它是一段二进制的内存空间,并不能直接构造和填充ArrayBuffer内容,要读写其内容应该先创建一个TypedArrayDataView视图。

2.1 语法结构

new ArrayBuffer(length)

创建一个ArrayBuffer对象可以调用其构造函数,创建时可以传入一个表示要创建数组长度的参数。

参数:

  • length-要创建二进制数组的长度

返回值:

  • ArrayBuffer-指定长度二进制数组实例


2.2 ArrayBuffer使用示例

创建一个8位的二进制数组,再创建一个Int32Array类型数组来读写这个数组:

var buffer = new ArrayBuffer(8);
var view = new Int32Array(buffer);

这样我们就创建了一个Int32类型的数组,通过这个数组我们可对二进制数组进行读写:

view[0]=1;
view[0];  // 1


3. TypedArray视图对象

TypedArray对象是一个描述二进制缓存数据(ArrayBuffer)的类似数组的视图对象。TypedArray对象由一组子对象构成,我们可以根据Buffer类型的不同而建立不同类型的数据视图,每种类型的视图都可以从不同的索引位置开始为缓存建立内容视图。

3.1 语法结构

new TypedArray(length);
new TypedArray(typedArray);
new TypedArray(object);
new TypedArray(buffer [, byteOffset [, length]]);

where TypedArray() is one of:

Int8Array();
Uint8Array();
Uint8ClampedArray();
Int16Array();
Uint16Array();
Int32Array();
Uint32Array();
Float32Array();
Float64Array();

TypedArray子类型的构造函数可以接受以三个参数:

  • ArrayBuffer-必须,底层的ArrayBuffer对象
  • byteOffset-可选,开始的偏移量(默认为0
  • length-可选,视图中包含的数据数(默认为缓存的数据总数)

TypedArray对象并不是一个独立或全局对象,它由以下9种子对象类型组成,每种子类型都有其自己的构造函数:

  • Int8Array:8位有符号整数,长度1个字节。
  • Uint8Array:8位无符号整数,长度1个字节。
  • Uint8ClampedArray:8位无符号整数,长度1个字节,溢出处理不同。
  • Int16Array:16位有符号整数,长度2字节。
  • Uint16Array:16位无符号整数,长度2字节。
  • Int32Array:32位有符号整数,长度4字节。
  • Uint32Array:32位无符号整数,长度4字节。
  • Float32Array:32位浮点数,长度4字节。
  • Float64Array:64位浮点数,长度8字节。


3.2 使用示例

对于一个ArrayBuffer对象,我们可以根据其类型的不同而建立多个不同类型视图,这些视图都来自TypedArray的子类型。示例如下:

// Setting and getting using standard array syntax
var int16 = new Int16Array(2);
int16[0] = 42;
console.log(int16[0]); // 42

// Indexed properties on prototypes are not consulted (Fx 25)
Int8Array.prototype[20] = "foo";
(new Int8Array(32))[20]; // 0
// even when out of bound
Int8Array.prototype[20] = "foo";
(new Int8Array(8))[20]; // undefined
// or with negative integers
Int8Array.prototype[-1] = "foo";
(new Int8Array(8))[-1]; // undefined

// Named properties are allowed, though (Fx 30)
Int8Array.prototype.foo = "bar";
(new Int8Array(32)).foo; // "bar"


4. DataView

DataView视图对象提供了一个更底层访问接口,通过这个接口我们可以读写多个ArrayBuffer,而且这些访问接口是与平台无关的格式类型。

4.1 语法结构

new DataView(buffer [, byteOffset [, length]])

DataView视图提供更多操作选项,用于ArrayBufferTypedArray对象中的子类型其更偏向于处理本机的二进制数据(如:网卡、声卡等二进制数据),而DataView更偏向于处理网络设备传来的数据,这个对象具有更多的可设置性。

DataView构造函数参数与TypedArray参数相同:

  • ArrayBuffer-必须,底层的ArrayBuffer对象
  • byteOffset-可选,开始的偏移量(默认为0
  • length-可选,视图中包含的数据数(默认为缓存的数据总数)


4.2 DataView使用示例

DataView视图在初始化时并不需要指定数据类型,但它提供了一系列实例方法,通过这些方法可以设置写入的数据类型(如:setInt8()设置写入8位整型)或读取数据类型(如:getInt8()读取8位整型):

var buffer = new ArrayBuffer(16);
var dv = new DataView(buffer, 0);

dv.setInt16(1, 42);
dv.getInt16(1); //42