javascript中的数组是个强大的家伙:你可以创建的时候不规定长度,而是动态的去改变长度。你可以把他当成普通的数组去读取,也可以当他是堆栈来使用。你可以改变数组中每个元素的值甚至是类型

Javascript中的数组是个强大的家伙:你可以创建的时候不规定长度,而是动态的去改变长度。你可以把他当成普通的数组去读取,也可以当他是堆栈来使用。你可以改变数组中每个元素的值甚至是类型。

好吧,其实他是一个对象,比如我们可以这样去创建数组:
 

复制代码

代码如下:


var array = new Array(10);


Javascript的数组的强大以及全能,给我们带来了便捷性。但一般而言:

全能的东西能在各种环境下使用,但却不一定适用于各种环境。

而TypedArray正是为了解决Javascript中数组“干太多事”而出现的。

HTML5引入的新数组TypedArray介绍_浮点数

起源

TypedArray是一种通用的固定长度缓冲区类型,允许读取缓冲区中的二进制数据。

其在WEBGL规范中被引入用于解决Javascript处理二进制数据的问题。

TypedArray已经被大部分现代浏览器支持,例如可以用下面方法创建TypedArray:
 

复制代码

代码如下:


// 创建一个8-byte的ArrayBuffer
var b = new ArrayBuffer(8);
// 创建一个b的引用,类型是Int32,起始位置在0,结束位置为缓冲区尾部
var v1 = new Int32Array(b);
// 创建一个b的引用,类型是Uint8,起始位置在2,结束位置为缓冲区尾部
var v2 = new Uint8Array(b, 2);
// 创建一个b的引用,类型是Int16,起始位置在2,总长度为2
var v3 = new Int16Array(b, 2, 2);


则缓冲和创建的引用布局为:

 

变量 索引
  字节数
b = 0 1 2 3 4 5 6 7
  索引数
v1 = 0 1
v2 =   0 1 2 3 4 5
v3 =   0 1  


这表示Int32类型的v1数组的第0个元素是ArrayBuffer类型的b的第0-3个字节,如此等等。构造函数

 

上面我们通过ArrayBuffer来创建TypedArray,而实际上,TypedArray提供了3个构造函数来创建他的实例。

构造函数

复制代码

代码如下:


TypedArray(unsigned long length)
创建一个新的TypedArray,length是其固定长度。

 

复制代码

代码如下:


TypedArray(TypedArray array)
TypedArray(type[] array)
创建一个新的TypedArray,其每个元素根据array进行初始化,元素进行了相应的类型转换。

 

复制代码

代码如下:


TypedArray(ArrayBuffer buffer, optional unsigned long byteOffset, optional unsigned long length)
创建一个新的TypedArray,使其作为buffer的一个引用,byteOffset为其起始的偏移量,length为其长度。


所以通常我们用下面的方式创建TypedArray:

 

复制代码

代码如下:


var array = new Uint8Array(10);


或者:

 

复制代码

代码如下:


var array = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);

 
数据操作

TypedArray提供了setter、getter、set和subarray四个方法进行数据操作。

方法getter type get(unsigned long index)

返回指定索引的元素。

setter void set(unsigned long index, type value)

设置指定索引的元素为指定值。

void set(TypedArray array, optional unsigned long offset)void set(type[] array, optional unsigned long offset)

根据array设置值,offset为偏移位置。

TypedArray subarray(long begin, optional long end)

返回一个新的TypedArray,起始位为begin,结束位为end。

例如读取元素可以用

var array = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);alert(array[4]); //5

设置元素可以用

var array = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);alert(array[4]); //5array[4] = 12;alert(array[4]); //12

获取一个副本可以用

var array = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);var array2 = array.subarray(0);数组类型

 

类型 大小 描述 Web IDL类型 C 类型
Int8Array 1 8位有符号整数 byte signed char
Uint8Array 1 8位无符号整数 octet unsigned char
Uint8ClampedArray 1 8位无符号整数 (clamped) octet unsigned char
Int16Array 2 16位有符号整数 short short
Uint16Array 2 16位无符号整数 unsigned short unsigned short
Int32Array 4 32位有符号整数 long int
Uint32Array 4 32位无符号整数 unsigned long unsigned int
Float32Array 4 32位IEEE浮点数 unrestricted float float
Float64Array 8 64位IEEE浮点数 unrestricted double double


玩过canvas的可能会觉得很眼熟。

因为ImageData中用于存储图像数据的数组便是Uint8ClampedArray类型的。

例如:

var context = document.createElement("canvas").getContext("2d");var imageData = context.createImageData(100, 100);console.log(imageData.data);

其在FireBug中显示为

Uint8ClampedArray { 0=0, 1=0, 2=0, 更多...}

为什么要用TypedArray

我们知道Javascript中数字是64位浮点数。则对于一个二进制图片(图片每个像素点是以8位无符号整数存储的),如果要将其数据在Javascript数组中使用,相当于使用了图片8倍的内存来存储一个图片的数据,这显然是不科学的。而TypedArray能帮助我们只使用原来1/8的内存来存储图片数据。

或者对于WebSocket,如果用base64进行传输也是一个花费较高的方式,转而使用二进制传送可能是更好的方式。

当然,TypedArray还有更多好处,比如具有更好的性能,下面我们进行一些小测试来验证这一点。

参与测试的浏览器为

FireFox 17.0.1 和 Chrome 23.0.1271.97m

Test1:顺序读取速读
 

复制代码

代码如下:


var timeArray1 = [];
var timeArray2 = [];
function check1(){
var array = new Uint8ClampedArray(5000000);
for(var i = array.length; i--;){
array[i] = Math.floor(Math.random() * 100);
}
var temp;
var time1 = (new Date()).getTime();
for(var i = array.length; i--;){
temp = array[i];
}
var time2 = (new Date()).getTime();
console.log(time2 - time1);
timeArray1.push(time2 - time1);
}
function check2(){
var array2 = new Array(5000000);
for(var i = array2.length; i--;){
array2[i] = Math.floor(Math.random() * 100);
}
var temp;
var time3 = (new Date()).getTime();
for(var i = array2.length; i--;){
temp = array2[i];
}
var time4 = (new Date()).getTime();
console.log(time4 - time3);
timeArray2.push(time4 - time3);
}
function timer(__fun, __time, __callback){
var now = 0;
function begin(){
var timeout = setTimeout(function(){
if(now !== __time){
now++;
__fun();
begin();
}else{
if(timeArray1.length && timeArray2.length){
console.log("timeArray1 == " + timeArray1 + ", average == " + average(timeArray1));
console.log("timeArray2 == " + timeArray2 + ", average == " + average(timeArray2));
}
__callback && __callback();
}
}, 100);
}
begin();
}
function average(__array){
var total = 0;
for(var i = __array.length; i--;){
total += __array[i];
}
return (total / __array.length);
}
timer(check1, 10, function(){
timer(check2, 10);
});

 

 

HTML5引入的新数组TypedArray介绍_浮点数_02

 

 

可见Uint8ClampedArray的读取速度明显比Array要快(条状柱越长,代表花费时间越多)。

 

Test2:随机读取

 

 

复制代码

代码如下:


//……
function check1(){
var array = new Uint8ClampedArray(5000000);
for(var i = array.length; i--;){
array[i] = Math.floor(Math.random() * 100);
}
var temp;
var time1 = (new Date()).getTime();
for(var i = array.length; i--;){
temp = array[Math.floor(Math.random() * 5000000)];
}
var time2 = (new Date()).getTime();
console.log(time2 - time1);
timeArray1.push(time2 - time1);
}
function check2(){
var array2 = new Array(5000000);
for(var i = array2.length; i--;){
array2[i] = Math.floor(Math.random() * 100);
}
var temp;
var time3 = (new Date()).getTime();
for(var i = array2.length; i--;){
temp = array2[Math.floor(Math.random() * 5000000)];
}
var time4 = (new Date()).getTime();
console.log(time4 - time3);
timeArray2.push(time4 - time3);
}
//……

 

HTML5引入的新数组TypedArray介绍_数据_03

 

随即读取中Uint8ClampedArray的读取速度也是比Array要快的。

 

Test3:顺序写入

 

 

复制代码

代码如下:


//……
function check1(){
var array = new Uint8ClampedArray(5000000);
var time1 = (new Date()).getTime();
for(var i = array.length; i--;){
array[i] = Math.floor(Math.random() * 100);
}
var time2 = (new Date()).getTime();
console.log(time2 - time1);
timeArray1.push(time2 - time1);
}
function check2(){
var array2 = new Array(5000000);
var time3 = (new Date()).getTime();
for(var i = array2.length; i--;){
array2[i] = Math.floor(Math.random() * 100);
}
var time4 = (new Date()).getTime();
console.log(time4 - time3);
timeArray2.push(time4 - time3);
}
//……

 

 

HTML5引入的新数组TypedArray介绍_数组_04

Test4:复制操作(U8C to U8C 和 Array to U8C)

 

 

 



HTML5引入的新数组TypedArray介绍_数组_05

 

 

复制代码

代码如下:


//……
function check1(){
var array = new Uint8ClampedArray(5000000);
for(var i = array.length; i--;){
array[i] = Math.floor(Math.random() * 100);
}
var temp;
var array2 = new Uint8ClampedArray(5000000);
var time1 = (new Date()).getTime();
array2.set(array);
var time2 = (new Date()).getTime();
console.log(time2 - time1);
timeArray2.push(time2 - time1);
}
function check2(){
var array = new Array(5000000);
for(var i = array.length; i--;){
array[i] = Math.floor(Math.random() * 100);
}
var temp;
var array2 = new Uint8ClampedArray(5000000);
var time1 = (new Date()).getTime();
array2.set(array);
var time2 = (new Date()).getTime();
console.log(time2 - time1);
timeArray2.push(time2 - time1);
}
//……

 

可见U8C复制到U8C,比Array复制到U8C快得多。

 

------------------------------------------------------------------------------------------

msdn上uint8Array介绍

 

Uint8Array 对象

 

8 位无符号整数值的类型化数组。内容将初始化为 0。如果无法分配请求数目的字节,则将引发异常。

 

语法

      uint8Array = new Uint8Array( length );
uint8Array = new Uint8Array( array );
uint8Array = new Uint8Array( buffer, byteOffset, length);

 

参数

uint8Array

必选。 Uint8Array 对象分配到的变量名称。

length

指定数组中元素的数目。

array

该数组中包含的数组(或类型化数组)。内容将初始化为给定数组或类型化数组的内容,且每个元素均转换为 Uint8 类型。

buffer

Uint8Array 表示的 ArrayBuffer。

byteOffset

可选。指定与 Uint8Array 将开始的缓冲区开始处的偏移量(以字节为单位)。

length

数组中的元素数。

 

常量

下表列出了 Uint8Array 对象的常量。

常量

说明

BYTES_PER_ELEMENT 常量

数组中每个元素的大小(以字节为单位)。

 

属性

下表列出了 Uint8Array 对象的常量。

属性

说明

buffer 属性

只读。获取此数组引用的 ArrayBuffer。

byteLength 属性

只读。此数组距离其 ArrayBuffer 开始处的长度(以字节为单位),在构造时已固定。

byteOffset 属性

只读。此数组与其 ArrayBuffer 开始处的偏移量(以字节为单位),在构造时已固定。

length 属性

数组的长度。

   

 

方法

下表列出了 Uint8Array 对象的方法。

方法

说明

set 方法 (Uint8Array)

设置值或值数组。

subarray 方法 (Uint8Array)

为此数组获取 ArrayBuffer 存储的新 Uint8Array 视图。

以下示例演示如何使用 Uint8Array 对象处理从 XmlHttpRequest 获取的二进制数据:

JavaScript

var req = new XMLHttpRequest();
    req.open('GET', "http://www.example.com");
    req.responseType = "arraybuffer";
    req.send();

    req.onreadystatechange = function () {
        if (req.readyState === 4) {
            var buffer = req.response;
            var dataview = new DataView(buffer);
            var ints = new Uint8Array(buffer.byteLength);
            for (var i = 0; i < ints.length; i++) {
                ints[i] = dataview.getUint8(i);
            }
        alert(ints[10]);
        }
    }

要求

 

在以下文档模式中受支持:Internet Explorer 10 标准模式和 Internet Explorer 11 标准模式。此外,也在应用商店应用(Windows 8 和 Windows Phone 8.1)中受支持。请参阅版本信息

在以下文档模式中不受支持:Quirks、Internet Explorer 6 标准模式、Internet Explorer 7 标准模式、Internet Explorer 8 标准模式、Internet Explorer 9 标准模式。