你所不知道的JavaScript数组
相信每一个 javascript 学习者,都会去了解 JS 的各种基本数据类型,数组就是数据的组合,这是一个很基本也十分简单的概念,他的内容没多少,学好它也不是件难事情。但是本文着重要介绍的并不是我们往常看到的 Array,而是 ArrayBuffer。
我写的很多东西都是因为要完成某些特定的功能而刻意总结的,可以算是备忘,本文也是如此!前段时间一直在研究 Web Audio API 以及语音通信相关的知识,内容侧重于音频流在 AudioContext 各个节点之间的流动情况,而现在要摸清楚音频到流底是个什么样的数据格式,所以对 ArrayBuffer 的研究就显得格外重要了。
本文地址:http://www.cnblogs.com/hustskyking/p/javascript-array.html,转载请注明源地址。
一、Array 在内存中的堆栈模型
1. Array 的获取
Javascript 中如何产生 Array:
- [element0, element1, ..., elementN]
- new Array(element0, element1, ..., elementN)
- new Array(arrayLength)
直接定义,或者通过构造函数创建一个 Array,当然也可以使用其他的手段:
- "array".split("");
- "array".match(/a|r/g);
等等,方式有很多。但是 Array 内部是个什么样的结构,恐怕很多人还不是很清楚。
2. 堆栈模型
在数组中我们可以放很多不同数据类型的数据,如:
- var arr = [21, "李靖", new Date(), function(){}, , null];
上面这个数组中一次放入了 数字、字符串、对象、函数、undefined 和 null,对于上面的数据接口我们可以具象的描述下:
- 栈
- +---------+ 堆
- | | +-------------------+
- +---------+ | |
- | "李靖" | | |
- +---------+ | +--------+ |
- | [refer] |----------->| Object | |
- +---------+ | +--------+ |
- | [refer] |----------------->+--------+ |
- +---------+ | |function| |
- |undefined| | +--------+ |
- +---------+ | |
- | null | +-------------------+
- +---------+ Created By Barret Lee
JavaScript 的数据类型分为两种,一种是值类型,一种是引用类型,常见的引用类型有 Object 和 Array,数组的储存模型中,如果是诸如 Number、String 之类的值类型数据会被直接压入栈中,而引用类型只会压入对该值的一个索引,用 C 语言的概念来解释就是只保存了数据的指针,这些数据是储存在堆中的某块区间中。栈堆并不是独立的,栈也可以在堆中存放。
好了,对 Array 的说明就到这里,下面具体说说 ArrayBuffer 的相关知识。
二、ArrayBuffer
web 是个啥玩意儿,web 要讨论的最基本问题是什么?我觉得有两点,一个是数据,一个是数据传输,至于数据的展示,纷繁复杂,这个应该是 web 上层的东西。而本文要讨论的 ArrayBuffer 就是最基础的数据类型,甚至不能称之为数据类型,它是一个数据容器,需要通过其他方式来读写。
官方点的定义:
The ArrayBuffer is a data type that is used to represent a generic, fixed-length binary data buffer. You can't directly manipulate the contents of an ArrayBuffer; instead, you create an ArrayBufferView object which represents the buffer in a specific format, and use that to read and write the contents of the buffer.
表示二进制数据的原始缓冲区,该缓冲区用于存储各种类型化数组的数据。 无法直接读取或写入 ArrayBuffer,但可根据需要将其传递到类型化数组或 DataView 对象 来解释原始缓冲区。
他是一个二进制数据的原始缓冲区,虽然 JavaScript 是弱类型语言,但是他本身是对数据的类型和大小都有限制的,我们需要通过某种数据结构将缓冲区的内容有序的读取出来(写进去)。
1. 原始缓冲区的创建
通过 ArrayBuffer 这个构造函数可以创建一个原始缓冲区:
- var buffer = new ArrayBuffer(30);
从 chrome 控制台可以看到:
buffer 实例拥有一个 byteLength 的属性,用于获取 buffer 的 size,一个只有 IE11+ 以及 ios6+ 支持的 slice 方法,用于对 buffer 长度进行截取操作。
- ArrayBuffer slice(
- unsigned long begin
- unsigned long end Optional
- );
可以测试这个 DEMO:
- var buffer = new ArrayBuffer(12);
- var x = new Int32Array(buffer);
- x[1] = 1234;
- var slice = buffer.slice(4);
- var y = new Int32Array(slice);
- console.log(x[1]);
- console.log(y[0]);
- x[1] = 6789;
- console.log(x[1]);
- console.log(y[0]);
2. 类型化数组
类型化数组类型表示可编制索引和操纵的 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:
- var x = new Float32Array(2);
- x[0] = 17;
- console.log(x[0]); //
- console.log(x[1]); //
- console.log(x.length); //
需要有这么一个概念,他依然是一个数组,只不过该数组中的每个元素都是 Float 32 位的数据类型,再如:
- var x = new Float32Array([17, -45.3]);
- console.log(x[0]); //
- console.log(x[1]); // -45.29999923706055
- console.log(x.length); //
我们把一个数组的值直接赋给了 x 这个 Float32Array 对象,那么在储存之前会将它转换成一个 32位浮点数。
由于该类数组的每个元素都是同一类型,所以在堆栈模型中,他们全部会被压入到栈之中,因此类型化数组都是值类型,他并不是引用类型!这个要引起注意,从下面的例子中也可以反映出来:
- var x = new Float32Array([17, -45.3]);
- var y = new Float32Array(x);
- console.log(x[0]); //
- console.log(x[1]); //-45.29999923706055
- console.log(x.length); //
- x[0] = -2;
- console.log(y[0]); // 17, y的值没变
将 x 的值复制给 y,修改 x[0], y[0] 并没有变化。
除了上面的方式,我们还可以通过其他方式来创建一个类型化数组:
- var buffer = new ArrayBuffer(12);
- var x = new Float32Array(buffer, 0, 2);
- var y = new Float32Array(buffer, 4, 1);
- x[1] = 7;
- console.log(y[0]); //
解释下这里为什么返回 7.
- ArrayBuffer()
- +-+-+-+-+-+-+-+-+-+-+-+-+-+
- |||||||||| | | | |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+
- \ /
- x (Float32Array)
- offset:
- byteLength:
- length:
- ArrayBuffer()
- +-+-+-+-+-+-+-+-+-+-+-+-+-+
- |||||||||| | | | |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+
- \ /
- y
- Created By Barret Lee
看了上面的图解还有疑问么?我觉得我不用继续解释了。可以把 ArrayBuffer 的单位看成 1,而 Float32Array 的单位是 4.
3. DataView对象
DataView 对象对数据的操作更加细致,不过我觉得没啥意思,上面提到的各种类型化数组已经可以基本满足应用了,所以这里就一笔带过,一个简单的示例:
- var buffer = new ArrayBuffer(12);
- var x = new DataView(buffer, 0);
- x.setInt8(0, 22);
- x.setFloat32(1, Math.PI);
- console.log(x.getInt8(0)); //
- 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
举个栗子:
- var xhr = new XMLHttpRequest();
- xhr.open('GET', '/path/to/image.png', true);
- xhr.responseType = 'arraybuffer';
- xhr.onload = function(e) {
- // this.response == uInt8Array.buffer
- var uInt8Array = new Uint8Array(this.response);
- };
- xhr.send();
我们在 xhr.responseType 中设置了属性为 arraybuffer,那么在拿到的数据中就可以用类型化数组来接受啦!
四、小结
本文主要介绍了 Array 在堆栈模型中的存放方式,也详细描述了 ArrayBuffer 这个原始缓冲区的二进制数据类型,在 web 开发中,数据以及数据的储存是一个重要的部分,希望引起注意!
本文叙述上可能存在错误,请多多斧正!
五、参考资料
- http://www.javascripture.com/ArrayBuffer
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array MDN Array
- http://www.html5rocks.com/zh/tutorials/file/xhr2/ html5rocks
- http://technet.microsoft.com/zh-cn/ie/br212485 MSDN
你所不知道的JavaScript数组的更多相关文章
- 你所不知道的javascript数组特性
工作中,我们经常使用js的数组,但是,下面的东西你见过吗? 1,文本下标: var a=[]; a[-1]=1; 你想过数组的下标为负数的情况吗?我们对数组的下标规定从0开始.但是上面那么写也还是可以 ...
- js值----你所不知道的JavaScript系列(6)
1.数组 在 JavaScript 中,数组可以容纳任何类型的值,可以是字符串.数字.对象(object),甚至是其他数组(多维数组就是通过这种方式来实现的) .----<你所不知道的JavaS ...
- js类型----你所不知道的JavaScript系列(5)
ECMAScirpt 变量有两种不同的数据类型:基本类型,引用类型.也有其他的叫法,比如原始类型和对象类型等. 1.内置类型 JavaScript 有七种内置类型: • 空值(null) • 未定义( ...
- 闭包----你所不知道的JavaScript系列(4)
一.闭包是什么? · 闭包就是可以使得函数外部的对象能够获取函数内部的信息. · 闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分. · 闭包就 ...
- 提升----你所不知道的JavaScript系列(3)
很多编程语言在执行的时候都是自上而下执行,但实际上这种想法在JavaScript中并不完全正确, 有一种特殊情况会导致这个假设是错误的.来看看下面的代码, a = 2; var a; console. ...
- let和const----你所不知道的JavaScript系列(2)
let 众所周知,在ES6之前,声明变量的关键字就只有var.var 声明变量要么是全局的,要么是函数级的,而无法是块级的. var a=1; console.log(a); console.log( ...
- LHS 和 RHS----你所不知道的JavaScript系列(1)
变量的赋值操作会执行两个动作, 首先编译器会在当前作用域中声明一个变量(如果之前没有声明过), 然后在运行时引擎会在作用域中查找该变量, 如果能够找到就会对它赋值.----<你所不知道的Ja ...
- JavaScript中你所不知道的Object(二)--Function篇
上一篇(JavaScript中你所不知道的Object(一))说到,Object对象有大量的内部属性,而其中多数和外部属性的操作有关.最后留了个悬念,就是Boolean.Date.Number.Str ...
- 你所不知道的setInterval
在你所不知道的setTimeout记载了下setTimeout相关,此篇则整理了下setInterval:作为拥有广泛应用场景(定时器,轮播图,动画效果,自动滚动等等),而又充满各种不确定性的这set ...
随机推荐
- python的Template
Template模块,可以用来制作web页面的模板,非常的方便. Template属于string中的一个类,所以要使用的话要在头部引入: from string import Template 模板 ...
- 解决报错 ora-00704 ora-00604 ora-00942 启动不了数据库问题
早上海南的同事打电话说他们的审计库连不上了启动也报错,问了下最近做了些什么操作,答复是之前添加了一次磁盘. 猜测是添加磁盘启动后/dev/sdx顺序出错,或者没有正常的关闭数据库导致数据库无法正常启动 ...
- 图文介绍如何在Eclipse统计代码行数(转)
使用Eclipse可以方便的统计工程或文件的代码行数,方法如下: 1.点击要统计的项目或许文件夹,在菜单栏点击Search,然后点击File... 2.选中正则表达式(Regular expressi ...
- POI的入门
POI快速入门 POI开发需要的七个步骤: 1.创建工作薄WorkBook对象 Workbook wb = new HSSFWorkbook(); //它是操作excel 2003版本 2.创建一个工 ...
- c程序对于文件的处理
C 文件读写 上一章我们讲解了 C 语言处理的标准输入和输出设备.本章我们将介绍 C 程序员如何创建.打开.关闭文本文件或二进制文件. 一个文件,无论它是文本文件还是二进制文件,都是代表了一系列的字节 ...
- [转]webpack
什么是 webpack? webpack是近期最火的一款模块加载器兼打包工具,它能把各种资源,例如JS(含JSX).coffee.样式(含less/sass).图片等都作为模块来使用和处理. 我们可以 ...
- RStudio技巧02_Extract Function
RStudio 可以在 source 编辑器中分析一组选择的代码,并自动将其转化成再次使用的函数.任何选择中的"free"变量( 选择引用对象但不创建)将转化为函数参数. (也可使 ...
- 【BZOJ1497】[NOI2006]最大获利 最小割
裸的最小割,很经典的模型. 建图:要求总收益-总成本最大,那么将每条弧与源点相连,流量为成本,每个收益与汇点相连,流量为收益,然后每条弧与它所能到达的收益相连,流量为inf. 与源点相连的是未被选中的 ...
- git flow工作流实际项目实践
公司项目的开发流程主要是这样 代码分为 develop分支 master分支 平时我开发的时候,主要在develop分支上改动 一般来讲,有以下几种改动方式 1.直接在develop上修改代码 这种一 ...
- java 测试:iterator foreach for 三种迭代方式哪种更快?
代码: public class main { public static void main(String[] p_args){ ArrayList<String> _l_string ...