zl程序教程

您现在的位置是:首页 >  前端

当前栏目

JavaScript中的ArrayBuffer详细介绍

JavaScript 详细 介绍
2023-06-13 09:15:32 时间

相信每一个javascript学习者,都会去了解JS的各种基本数据类型,数组就是数据的组合,这是一个很基本也十分简单的概念,他的内容没多少,学好它也不是件难事情。但是本文着重要介绍的并不是我们往常看到的Array,而是ArrayBuffer。

我写的很多东西都是因为要完成某些特定的功能而刻意总结的,可以算是备忘,本文也是如此!前段时间一直在研究WebAudioAPI以及语音通信相关的知识,内容侧重于音频流在AudioContext各个节点之间的流动情况,而现在要摸清楚音频到流底是个什么样的数据格式,所以对ArrayBuffer的研究就显得格外重要了。

Array在内存中的堆栈模型

Array的获取

Javascript中如何产生Array:

复制代码代码如下:

[element0,element1,...,elementN]
newArray(element0,element1,...,elementN)
newArray(arrayLength)

直接定义,或者通过构造函数创建一个Array,当然也可以使用其他的手段:

复制代码代码如下:


"array".split("");
"array".match(/a|r/g);

等等,方式有很多。但是Array内部是个什么样的结构,恐怕很多人还不是很清楚。

堆栈模型

在数组中我们可以放很多不同数据类型的数据,如:

复制代码代码如下:
vararr=[21,"李靖",newDate(),function(){},,null];

上面这个数组中一次放入了数字、字符串、对象、函数、undefined和null,对于上面的数据接口我们可以具象的描述下:

复制代码代码如下:
 栈
+---------+                 堆
|  21   |        +-------------------+
+---------+        |                  |
| "李靖"|        |                  |
+---------+        | +--------+      |
|[refer]|----------->|Object|      |
+---------+        | +--------+      |
|[refer]|----------------->+--------+|
+---------+        |       |function||
|undefined|        |       +--------+|
+---------+        |                  |
|  null |        +-------------------+
+---------+        CreatedByBarretLee

JavaScript的数据类型分为两种,一种是值类型,一种是引用类型,常见的引用类型有Object和Array,数组的储存模型中,如果是诸如Number、String之类的值类型数据会被直接压入栈中,而引用类型只会压入对该值的一个索引,用C语言的概念来解释就是只保存了数据的指针,这些数据是储存在堆中的某块区间中。栈堆并不是独立的,栈也可以在堆中存放。

好了,对Array的说明就到这里,下面具体说说ArrayBuffer的相关知识。

ArrayBuffer

web是个啥玩意儿,web要讨论的最基本问题是什么?我觉得有两点,一个是数据,一个是数据传输,至于数据的展示,纷繁复杂,这个应该是web上层的东西。而本文要讨论的ArrayBuffer就是最基础的数据类型,甚至不能称之为数据类型,它是一个数据容易,需要通过其他方式来读写。

官方点的定义:

TheArrayBufferisadatatypethatisusedtorepresentageneric,fixed-lengthbinarydatabuffer.Youcan"tdirectlymanipulatethecontentsofanArrayBuffer;instead,youcreateanArrayBufferViewobjectwhichrepresentsthebufferinaspecificformat,andusethattoreadandwritethecontentsofthebuffer.
表示二进制数据的原始缓冲区,该缓冲区用于存储各种类型化数组的数据。无法直接读取或写入ArrayBuffer,但可根据需要将其传递到类型化数组或DataView对象来解释原始缓冲区。

他是一个二进制数据的原始缓冲区,虽然JavaScript是弱类型语言,但是他本身是对数据的类型和大小都有限制的,我们需要通过某种数据结构将缓冲区的内容有序的读取出来(写进去)。

原始缓冲区的创建

通过ArrayBuffer这个构造函数可以创建一个原始缓冲区:

复制代码代码如下:
varbuffer =newArrayBuffer(30);

从chrome控制台可以看到:

buffer实例拥有一个byteLength的属性,用于获取buffer的size,一个只有IE11+以及ios6+支持的slice方法,用于对buffer长度进行截取操作。

复制代码代码如下:
ArrayBufferslice(
   unsignedlongbegin
   unsignedlongendOptional
);

可以测试这个DEMO:

复制代码代码如下:
varbuffer=newArrayBuffer(12);
varx=newInt32Array(buffer);
x[1]=1234;
varslice=buffer.slice(4);
vary=newInt32Array(slice);
console.log(x[1]);
console.log(y[0]);
x[1]=6789;
console.log(x[1]);
console.log(y[0]);

数据化数组

类型化数组类型表示可编制索引和操纵的ArrayBuffer对象的各种视图。所有数组类型的长度均固定。

复制代码代码如下:
名称 大小(以字节为单位) 描述
Int8Array 1 8位二补码有符号整数
Uint8Array 1 8位无符号整数
Int16Array 2 16位二补码有符号整数
Uint16Array 2 16位无符号整数
Int32Array 4 32位二补码有符号整数
Uint32Array 4 32位无符号整数
Float32Array 4 32位IEEE浮点数
Float64Array 8 64位IEEE浮点数

Int就是整型,Uint为无符号整形,Float为浮点型,这些是C语言中的基本概念,我就不具体解释了。由于这些视图化结构都是大同小异,本文只对Float32Array类型作说明,读者可以举一反三。

Float32Array跟Array是十分类似的,只不过他每一个元素都是都是一个32位(4字节)的浮点型数据。Float32Array一旦创建其大小不能再修改。

我们可以直接创建一个Float32Array:

复制代码代码如下:
varx=newFloat32Array(2);
x[0]=17;
console.log(x[0]);//17
console.log(x[1]);//0
console.log(x.length);//2

需要有这么一个概念,他依然是一个数组,只不过该数组中的每个元素都是Float32位的数据类型,再如:

复制代码代码如下:
varx=newFloat32Array([17,-45.3]);
console.log(x[0]); //17
console.log(x[1]); //-45.29999923706055
console.log(x.length);//2

我们把一个数组的值直接赋给了x这个Float32Array对象,那么在储存之前会将它转换成一个32位浮点数。

由于该类数组的每个元素都是同一类型,所以在堆栈模型中,他们全部会被压入到栈之中,因此数据化数组都是值类型,他并不是引用类型!这个要引起注意,从下面的例子中也可以反映出来:

复制代码代码如下:
varx=newFloat32Array([17,-45.3]);
vary=newFloat32Array(x);
console.log(x[0]);//17
console.log(x[1]);//-45.29999923706055
console.log(x.length);//2
x[0]=-2;
console.log(y[0]);//17,y的值没变

将x的值复制给y,修改x[0],y[0]并没有变化。

除了上面的方式,我们还可以通过其他方式来创建一个数据化数组:

复制代码代码如下:
varbuffer=newArrayBuffer(12);
varx=newFloat32Array(buffer,0,2);
vary=newFloat32Array(buffer,4,1);
x[1]=7;
console.log(y[0]);//7

解释下这里为什么返回7.

复制代码代码如下:
 ArrayBuffer(12)
+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|1|2|3|4|5|6|7|8|||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+
\               /          
 x(Float32Array)
 offset:0
 byteLength:4
 length:2


      ArrayBuffer(12)
+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|1|2|3|4|5|6|7|8|||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+
       \        /          
            y

     CreatedByBarretLee

看了上面的图解还有疑问么?我觉得我不用继续解释了。可以把ArrayBuffer的单位看成1,而Float32Array的单位是4.

DataView对象

DataView对象对数据的操作更加细致,不过我觉得没啥意思,上面提到的各种数据化数组已经可以基本满足应用了,所以这里就一笔带过,一个简单的示例:

复制代码代码如下:
varbuffer=newArrayBuffer(12);
varx=newDataView(buffer,0);
x.setInt8(0,22);
x.setFloat32(1,Math.PI);
console.log(x.getInt8(0));//22
console.log(x.getFloat32(1));//3.1415927410125732

如果感兴趣,可以移步http://www.javascripture.com/DataView,作详细了解。

XHR2中的ArrayBuffer

ArrayBuffer的应用特别广泛,无论是WebSocket、WebAudio还是Ajax等等,前端方面只要是处理大数据或者想提高数据处理性能,那一定是少不了ArrayBuffer。

XHR2并不是什么新东西,可能你用到了相关的特性,却不知这就是XHR2的内容。最主要的一个东西就是xhr.responseType,他的作用是设置响应的数据格式,可选参数有:"text"、"arraybuffer"、"blob"或"document"。请注意,设置(或忽略)xhr.responseType=""会默认将响应设为"text"。这里存在一个这样的对应关系:

复制代码代码如下:
请求           响应
text           DOMString
arraybuffer    ArrayBuffer
blob           Blob
document       Document

举个栗子:

复制代码代码如下:
varxhr=newXMLHttpRequest();
xhr.open("GET","/path/to/image.png",true);
xhr.responseType="arraybuffer";

xhr.onload=function(e){
   //this.response==uInt8Array.buffer
   varuInt8Array=newUint8Array(this.response);
};

xhr.send();

我们在xhr.responseType中设置了属性为arraybuffer,那么在拿到的数据中就可以用数据化数组来接受啦!

小结

本文主要介绍了Array在堆栈模型中的存放方式,也详细描述了ArrayBuffer这个原始缓冲区的二进制数据类型,在web开发中,数据以及数据的储存是一个重要的部分,希望引起注意!

本文叙述上可能存在错误,请多多斧正!