理解 typed array

咱们知道在C语言中,可使用mallocfree方法来分配和释放内存。随着web的发展中,js在ES6中新增了内存操做的支持。其实现方式就是---typed array。web

typed array是个集体的概念。int8Array,Uint8Array,int16Array,Uint16Array等通通等称为typed array。经过这些类,开发者能够方便地读写内存中的二进制数据。数组

typed array在内部设计时分红了两部分:bufferviewbuffer层表示内存中的数据块,view负责提供操做数据块的接口。spa

ArrayBuffer

buffer层的底层实现就是基于ArrayBuffer类。ArrayBuffer的功能与malloc相似,为用户分配一块内存。设计

建立一个ArrayBuffer实例很简单,它接收一个参数,参数表示要分配多大的一块内存区域,字节为单位。下面的代码片断,分配了一块8字节的内存区:code

var buffer = new ArrayBuffer(8);

咱们还能够经过byteLength访问该实例的内存大小:对象

console.log(buffer.byteLength) // 8

使用slice方法建立一个新的实例,其内容复制原ArrayBuffer实例中的部份内容。索引

var buf2 = buffer.slice(0,2);

建立一个新的实例,分配2字节大小的内存,其内容复制buffer中索引为0和1的内存中的数据。接口

可是ArrayBuffer并不提供对内存读写的方法。若是要对该内存块进行操做,须要用到另外一个类DataView图片

DataView

DataView类提供了访问ArrayBuffer的接口。其语法以下:内存

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

首先接收一个必传的buffer对象,该对象就是DataView实例接下来将要操做的内存块。其次是一个可选的byteOffset,该参数表示DataView实例要操做的buffer对象的开始位置。最后的参数指定要操做的buffer对象中元素的个数。
下面的代码片断演示了DataView如何操做ArrayBuffer

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

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

示例中建立了一个DataView实例,该实例将buffer做为被操做的内存块,而且指定该内存块的16个字节都位于可操做区。
接着调用setInt16方法向从buffer的第2个字节开始存储带符号的16位整数。调用getInt16方法读出位于第2个字节处的带符号的16位整数。

typed array

如上所述,typed array的实现是组合了ArrayBufferDataView。也就是说typed array 经过ArrayBuffer建立内存块,经过DataView实现对内存块的读写操做。

typed array提供了多个类实现对同一块内存中的二进制数据按照不一样的位数格式进行读写。如使用int8Array从内存中以带符号的8位整数的形式读写数据。

下面看一个例子来加深对typed array的理解

var buffer = new ArrayBuffer(16) //建立16b的内存区
var int32View = new Int32Array(buffer);
var int16View = new Int16Array(buffer);

for (var i = 0; i < int32View.length; i++) {
  int32View[i] = i * 2;
  console.log(int32View[i]); // 0, 2, 4, 6
}

for (var i = 0; i < int16View.length; i++) {
  console.log(int16View[i]); // 0, 0, 2, 0, 4, 0, 6, 0
}

buffer是一个ArrayBuffer实例,表示一块16b的内存区。同时建立了两个typed array,分别是32位和16位的。区别在于使用32位的访问buffer时,会把buffer(16b)以32位为单位划分为4个元素,读写都是以32位为单位进行的。16位的进行访问时,会把buffer(16b)以16位为单位划分为8个元素,每次读写都是16位。

第一个循环中,咱们使用int32Viewbuffer中的4个元素中分别写入了0,2,4,6 4个整数。
很显然console中的结果是0,2,4,6

第二个循环中,咱们使用int16View以16位的格式读取同一块内存,能够想象原来的4个元素变成了8个元素,所以读出的时候也会将原来的32位元素拆分为2个16位元素。所以console中的结果是0,0,2,0,4,0,6,0

有同窗可能对输出的顺序不理解,以为为何不是0,0,0,2,0,4,0,6呢。这里稍微解释一下。
缘由是默认状况下typed array 读取数据的时候都是以小端模式来返回的。

所谓的小端模式(Little-endian),是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和咱们的逻辑方法一致。

上例在小端模式下的存储形式,每一个框框表示16位。小端模式下数据的位权和地址的顺序是一致的,从小到大排列。

图片描述

总结

typed array提供了一组读取不一样字长的类数组对象如,int8Array,int16Array,int64Array来实现对内存的操做。typed array的底层实现是基于ArrayBufferDataView实现的,对内存的分配和内存的读取作了很好的分层设计。使用typed array使js向C语言等具有了操做二进制数据的能力。

相关文章
相关标签/搜索