ArrayBuffer对象作为内存区域可以存放多种类型的数据。同一段内存,不同数据有不同的解读方式,这种解读方式称为“视图(view)”。ArrayBuffer有两种类型的视图,一种是类型化数组视图(TypedArray),另一种是数据视图(DataView)。类型化数组视图的数组成员都是同一个数据类型,后者的数组成员可以是不同的数据类型。

TypedArray视图一共有9种类型,每一种视图都是一个构造函数。

这些视图实现了数组接口,均有length属性,都可以使用方括号运算符来获取单个元素,所有数组方法都可以在其上面使用。普通数组和TypedArray数组的差异主要在以下方面:

1、TypedArray数组的所有成员都是同一种类型。

2、TypedArray数组的成员是连续的,不会有空位,不存在稀疏数组的情况。

3、TypedArray数组成员的默认值是0。

TypedArray数组只是一个视图,本身不存储数据,它的数据都存储在底层的ArrayBuffer对象中,要获取底层对象必须使用buffer属性。

TypedArray构造函数

TypedArray有四种形式的构造函数,分别是:

1、TypedArray(buffer, byteOffset, length)

参数buffer代表了视图底层的ArrayBuffer对象,byteOffset表示视图开始的字节序号,默认从0开始,length代表视图包含的数据个数,默认直到本段内存区域结束。

其中,byteOffset必须是与所要建立的数据类型的字节长度的整数倍,否则会出错。

var buffer = new ArrayBuffer(32);
var i16 = new Uint16Array(buffer, 1); // RangeError, Uint16的每个数据的长度为2个字节,故byteOffset必须是

2、TypedArray(length)

视图可以不通过ArrayBuffer对象,直接指定长度,分配相应的内存。构造函数的参数代表要分配的成员个数。

var i16 = new Int16Array(3); // 分配了3*2=6个字节的内存
i16.buffer.byteLength;       // 6

3、TypedArray(typedArray)

可以通过一个TypedArray实例来构建另一个TypedArray实例,两个实例的类型可以不一样,此时新实例只是复制了源实例的值,底层的内存是不一样的。

var source = new Uint16Array(16);
var target = new Int16Array(source);

4、TypedArray(arrayLikeObject)

可以通过一个类数组对象来创建TypedArray实例,数组对象的每一个值就是新实例数组的每一项对应的值。

var a = new Uint32Array([1,2,3,4]);
a[2]; // 3

TypedArray的属性

1、TypedArray有一个name属性,是用于描述类型数组的字符串值。九个类型数组的name属性分别是:

Int8Array.name;         // "Int8Array"
Uint8Array.name;        // "Uint8Array"
Uint8ClampedArray.name; // "Uint8ClampedArray"
Int16Array.name;        // "Int16Array"
Uint16Array.name;       // "Uint16Array"
Int32Array.name;        // "Int32Array"
Uint32Array.name;       // "Uint32Array"
Float32Array.name;      // "Float32Array"
Float64Array.name;      // "Float64Array"

2、BYTES_PER_ELEMENT属性表示这种数据类型的每个元素所占用的字节数。

Int8Array.BYTES_PER_ELEMENT;         // 1
Uint8Array.BYTES_PER_ELEMENT;        // 1
Uint8ClampedArray.BYTES_PER_ELEMENT; // 1
Int16Array.BYTES_PER_ELEMENT;        // 2
Uint16Array.BYTES_PER_ELEMENT;       // 2
Int32Array.BYTES_PER_ELEMENT;        // 4
Uint32Array.BYTES_PER_ELEMENT;       // 4
Float32Array.BYTES_PER_ELEMENT;      // 4
Float64Array.BYTES_PER_ELEMENT;      // 8

3、TypedArray实例的buffer属性返回整段内存区域对于的ArrayBuffer对象。该属性为只读属性。

var ab = new ArrayBuffer(32);
var ui16 = new Uint16Array(ab);
ui16.buffer === ab; // true
Object.getOwnPropertyDescriptor(Uint16Array.prototype.__proto__, 'buffer');
// {get: ƒ, set: undefined, enumerable: false, configurable: true}

4、TypedArray实例的byteLength属性返回TypedArray数组占据的内存长度,单位为字节。

var ab = new ArrayBuffer(32);
var ui16 = new Uint16Array(ab, 2);
ui16.byteLength; // 30

5、TypedArray实例的byteOffset属性表示TypedArray数组从底层ArrayBuffer对象的哪个字节开始。

var ab = new ArrayBuffer(32);
var ui16 = new Uint16Array(ab, 2);
ui16.byteOffset; // 2

6、TypedArray实例的length属性表示实例有多少个成员。

var ab = new ArrayBuffer(32);
var ui16 = new Uint16Array(ab, 2);
ui16.length; // 15

TypedArray构造函数的静态方法

TypedArray数组的所有构造函数上都有一个静态方法of,用于将参数转为一个TypedArray实例。

Float32Array.of(12.213, -8, 83.1); // [12.213, -8, 83.1]
// 也可以用下面的方法新建同样的数组
var a = new Float32Array([12.213, -8, 83.1]);
var b = new Float32Array(3);
b[0] = 12.213;
b[1] = -8;
b[2] = 83.1

TypedArray数组的另一个静态方法from()接受一个可遍历的数据结构(比如数组)作为参数,返回一个基于此结构的TypedArray实例。同时还可以接受第二个函数参数,在新建实例时,对每一个元素向映射到函数中,将函数的结果作为新实例的值。

Uint16Array.from([1,2,3]); // [1,2,3]
Uint16Array.from([1,2,3], value => value * 2); // [2,4,6]

TypedArray原型对象上的方法

由于TypedArray实现了数组接口,故可以在TypedArray上使用数组的方法来进行操作。

Object.getOwnPropertyNames(Uint16Array.prototype.__proto__);
/* [
"constructor",
"buffer",
"byteLength",
"byteOffset",
"length",
"entries",
"keys",
"values",
"copyWithin",
"subarray",
"set",
"every",
"fill",
"filter",
"find",
"findIndex",
"includes",
"indexOf",
"join",
"lastIndexOf",
"forEach",
"map",
"reduce",
"reduceRight",
"reverse",
"slice", "some",
"sort",
"toLocaleString",
"toString"] */

1、TypedArray.prototype.copyWithin(target, start[, end = this.length])

从原数组的start位置开始复制数据到end(不含),填充到target及以后的位置上,并返回修改后的数组。

var array = new Int16Array(10);
array.set([1,2,3]);
array; // [1, 2, 3, 0, 0, 0, 0, 0, 0, 0]
array.copyWithin(3, 0, 3);
array; // [1, 2, 3, 1, 2, 3, 0, 0, 0, 0]

2、TypedArray.prototype.entries()

返回TypedArray的键值对遍历器

var array = new Int16Array(3);
array.set([1,2,3]);
var iter = array.entries();
for (let element of iter) {console.log(element);
}
/*
[0,1]
[1,2]
[2,3]
*/

3、TypedArray.prototype.every(callback[, thisArg])

对数组的每一个元素都指向一次函数操作,如果每个元素都能通过测试,则返回true,否则返回false。

var array = new Int16Array(3);
array.set([1,2,3]);
array.every(function (value) { return value % 2 == 1;  }); // false 2不是奇数

4、TypedArray.prototype.fill(value[, start = 0[, end = this.length]])

使用指定值填充TypedArray从start到end(不含)的全部元素。

new Uint8Array([1, 2, 3]).fill(4);         // Uint8Array [4, 4, 4]
new Uint8Array([1, 2, 3]).fill(4, 1);      // Uint8Array [1, 4, 4]
new Uint8Array([1, 2, 3]).fill(4, 1, 2);   // Uint8Array [1, 4, 3]
new Uint8Array([1, 2, 3]).fill(4, 1, 1);   // Uint8Array [1, 2, 3]
new Uint8Array([1, 2, 3]).fill(4, -3, -2); // Uint8Array [4, 2, 3]

5、TypedArray.prototype.filter(callback[, thisArg])

对每个数组元素进行测试,保留通过测试函数的值。

function isBigEnough(element, index, array) {return element >= 10;
}
new Uint8Array([12, 5, 8, 130, 44]).filter(isBigEnough);
// Uint8Array [ 12, 130, 44 ]

6、TypedArray.prototype.find(callback[, thisArg])

返回第一个通过测试函数的值。如果没有一个元素通过测试,则返回undefined。

function isPrime(element, index, array) {var start = 2;while (start <= Math.sqrt(element)) {if (element % start++ < 1) {return false;}}return element > 1;
}var uint8 = new Uint8Array([4, 5, 8, 12]);
console.log(uint8.find(isPrime)); // 5

7、TypedArray.prototype.findIndex(callback[, thisArg])

返回第一个通过测试函数的值的下标。如果没有一个元素通过测试,则返回undefined。

function isPrime(element, index, array) {var start = 2;while (start <= Math.sqrt(element)) {if (element % start++ < 1) {return false;}}return element > 1;
}var uint16 = new Uint16Array([4, 5, 8, 12]);
console.log(uint16.findIndex(isPrime)); // 1

8、TypedArray.prototype.forEach(callback[, thisArg])

为每一个数组元素执行指定的函数。

function logArrayElements(element, index, array) {console.log('a[' + index + '] = ' + element);
}new Uint8Array([0, 1, 2, 3]).forEach(logArrayElements);
/*
a[0] = 0
a[1] = 1
a[2] = 2
a[3] = 3
*/

9、TypedArray.prototype.includes(searchElement[, fromIndex])

返回一个布尔值,表明数组中从下标fromIndex开始到结尾,是否包含了指定的搜索元素。

var uint8 = new Uint8Array([1,2,3]);
uint8.includes(2);     // true
uint8.includes(4);     // false
uint8.includes(3, 3);  // false// NaN 的处理 (仅仅对 Float32 和 Float64 为 true)
new Uint8Array([NaN]).includes(NaN); // false, 因为 NaN 传递给构造器时转换为 0
new Float32Array([NaN]).includes(NaN); // true;
new Float64Array([NaN]).includes(NaN); // true;

10、TypedArray.prototype.indexOf(searchElement[, fromIndex = 0])

在TypedArray中搜索元素,返回第一次出现的位置下标,如果找不到对应的元素,则返回-1。

let uint8 = new Uint8Array([2, 5, 9]);
uint8.indexOf(2);     // 0
uint8.indexOf(7);     // -1
uint8.indexOf(9, 2);  // 2
uint8.indexOf(2, -1); // -1
uint8.indexOf(2, -3); // 0

11、TypedArray.prototype.join([separator = ','])

将数值各个元素转为字符串,再使用separator将其各个字符串连接后返回。

var array = new Int16Array([1,2,3,4]);
var str = array.join('-');
str; // "1-2-3-4"

12、TypedArray.prototype.keys()

返回一个数组下标的遍历器。

var array = new Int16Array(3);
array.set([1,2,3]);
var iter = array.keys();
for (let index of iter) {console.log(index);
}
/*
0
1
2
*/

13、TypedArray.prototype.lastIndexOf(searchElement[, fromIndex = typedarray.length])

在TypedArray中搜索元素,返回最后一次出现的位置下标,如果找不到对应的元素,则返回-1。

const uint8 = new Uint8Array([2, 5, 9, 4, 5, 3]);
uint8.lastIndexOf(5); // 4

14、TypedArray.prototype.map(callback[, thisArg])

map方法对类型化数组中的元素调用提供的 callback函数,按照顺序,并且会从结果构造新的类型化数组。

const uint8 = new Uint8Array([2, 5, 9, 4, 5, 3]);
const new_ui8 = uint8.map(function (value) {return value * 2;
});
new_ui8; // [4,10,18,8,10,6]

15、TypedArray.prototype.reduce(callback[, initialValue])

reduce() 方法接受一个函数作为参数,这个函数作为一个累加器,从左到右遍历整个类型数组,最后返回一个单一的值。

const uint8 = new Uint8Array([2, 5, 9, 4, 5, 3]);
uint8.reduce(function (a, b) {return a + b;
}, 0); // 28

16、TypedArray.prototype.reduceRight(callback[, initialValue])

reduceRight()在累加器和类型化数组的每个元素上(从右到左)调用函数,使其归约为单一的值。

const uint8 = new Uint8Array([2, 5, 9, 4, 5, 3]);
uint8.reduceRight(function (a, b) {return a + b;
}); // 28

17、TypedArray.prototype.reverse()

原地逆序TypedArray数组。

const uint8 = new Uint8Array([2, 5, 9, 4, 5, 3]);
uint8.reverse(); // [3,5,4,9,5,2]

18、TypedArray.prototype.set(array [,offset])

set()方法用于从指定数组中读取值,并将其存储在类型化数组中。

var buffer = new ArrayBuffer(8);
var uint8 = new Uint8Array(buffer);
uint8.set([1,2,3], 3);
console.log(uint8); // Uint8Array [ 0, 0, 0, 1, 2, 3, 0, 0 ]

19、TypedArray.prototype.slice([begin[, end]])

返回一个指定位置的新的TypedArray实例。

const uint8 = new Uint8Array([2, 5, 9, 4, 5, 3]);
uint8.slice(2,5); // [9,4,5]

20、TypedArray.prototype.some(callback[, thisArg])

提供一个测试函数,当TypedArray中的某一个元素通过测试函数,则返回true。

const uint8 = new Uint8Array([2, 5, 9, 4, 5, 3]);
uint8.some(function (value) { return value > 5; }); // true

21、TypedArray.prototype.sort([compareFunction])

sort()方法原地排序类型化数组的元素,并且返回类型化数组。这个方法的算法和Array.prototype.sort()相同。

var numbers = new Uint8Array([40, 1, 5, 200]);
numbers.sort();
// Uint8Array [ 1, 5, 40, 200 ]
// 在这里,按数值排序数值时,
// 不需要比较函数。

22、TypedArray.prototype.subarray([begin [,end]])

对TypedArray数组的一部分再建立一个新的视图。第一个参数是起始的成员序号,第二个参数是结束的成员序号(不含该成员)如果省略则包含剩余的全部成员。新视图和源视图底层的ArrayBuffer是共用的。

const uint8 = new Uint8Array([2, 5, 9, 4, 5, 3]);
const new_uint8 = uint8.subarray(2, 5); // [9,4,5]
new_uint8[1] = 10;
new_uint8; // [9,10,5]
uint8; // [2,5,9,10,5,3]

23、TypedArray.prototype.toLocaleString()

toLocaleString()方法返回一个字符串,表明该类型化数组的元素。这些元素被转化为字符串并由一个区域设置指定的分隔符(例如逗号 “,”)分隔。这个方法与Array.prototype.toLocaleString()拥有相同的算法。同时,由于类型化数组的元素都是数,将每个元素转化为字符串的算法与Number.prototype.toLocaleString()是相同的。

var uint = new Uint32Array([2000, 500, 8123, 12, 4212]);
uint.toLocaleString('ja-JP', { style: 'currency', currency: 'JPY' });
// "¥2,000,¥500,¥8,123,¥12,¥4,212"

24、TypedArray.prototype.toString()

TypedArray 对象重写了Object的 toString方法。对 TypedArray 对象来说,toString 方法联结了数组,并返回一个字符串,它包含由逗号分隔的数组元素。

var numbers = new Uint8Array([2, 5, 8, 1, 4])
numbers.toString(); // "2,5,8,1,4"

25、TypedArray.prototype.values()

返回TypedArray的键值遍历器。

const uint8 = new Uint8Array([2, 5, 9, 4, 5, 3]);
var iter = uint8.values();
for (let ele of iter) {console.log(ele);
}
/*
2
5
9
4
5
3
*/

26、TypedArray.prototype[@@iterator]()

返回TypedArray键值对的遍历器,效果和values()方法一样。

const uint8 = new Uint8Array([2, 5, 9, 4, 5, 3]);
var iter = uint8[Symbol.iterator]();
for (let ele of iter) {console.log(ele);
}
/*
2
5
9
4
5
3
*/

TypedArray的字节序

字节序是指数值在内存中的表示方式。

var buffer = new ArrayBuffer(16);
var int32View = new Int32Array(buffer);
for (let i = 0; i < int32View.length; i++) {int32View[i] = i * 2;
}
int32View; // [0,2,4,6]

上述代码新建了一个16字节的内存区域,并在其上建了一个32位(4字节)的视图,该视图有4个元素,对元素分别赋值为0,2,4,6。如果对该内存区域上新建一个16位(2字节)的视图,我们可以看出数据的存储方式。

var int16View = new Int16Array(buffer);
for (let value of int16View) {console.log(value);
}
/*
0
0
2
0
4
0
6
0
*/

用图来说明如下:

由于x86体系的计算机都采用小端字节序,相对重要的字节排在后面的内存地址,相对不重要的字节排在前面的内存地址。

比如,一个占据4字节的十六进制数0x12345678,决定其大小的最重要的字节是“12”,最不重要的是“78”,故在内存中,存储顺序是“78563412”。TypedArray数组内部也采用的是本机操作系统设定的字节序读写数据。

TypedArray对溢出的处理

不同的视图类型所能容纳的数值范围是确定的,超出这个范围就会出现溢出。

TypedArray数组对于溢出采用的处理方法是求余值。正向溢出的含义是指输入值大于可容纳的当前数据类型的最大值,最后得到的值等于当前数据类型的最小值加上余值,再减去1。负向溢出等于当前数据类型的最大值减去余值,再加上1。

// 无符号单字节整型可容纳的最大数值是255,最小数值是0
var uint8 = new Uint8Array(1);
uint8[0] = 256; // 正向溢出,超出最大值范围,余值是1
uint8[0]; // 0 最小值+余值-1=0uint8[0] = -12; // 负向溢出,超出最小值范围,余值是12
uint8[0]; // 最大值-余值+1=255-12+1=244

UInt8ClampedArray视图的溢出与其他8种类型的规则有所不同。负向溢出的值都是0,正向溢出的值都是255。

var a = new Uint8ClampedArray(1);
a[0] = 2112;
a[0]; // 255
a[0] = -123
a[0]; // 0

利用TypedArray构建复合视图

由于视图的构造函数可以指定起始位置和长度,所以在同一段内存中可以依次存放不同类型的数据,这就叫复合视图。

var ab = new ArrayBuffer(24);
var idView = new Uint32Array(buffer, 0, 1);
var userNameView = new Uint8Array(buffer, 4, 16);
var amountView = new Float32Array(buffer, 20, 1);

上面的代码将一个24字节的内存分成3个部分:

字节0到字节3,1个32位无符号整数,用于存放ID。

字节4到字节19存放16个8位无符号整数。

剩下4个字节存放1个32位浮点数。

这样数据接口用C语言描述如下:

struct User {unsigned int id;char[16] username;float amount;
};


同系列文章:

《JavaScript二进制数组(1)ArrayBuffer》

《JavaScript二进制数组(2)TypedArray视图》

《JavaScript二进制数组(3)DataView视图》

将视图转为image_JavaScript二进制数组(2)TypedArray视图相关推荐

  1. Threejs 拓展之二进制数组

    在Threejs 的学习过程中,分配缓存区域时需要调用JavaScript中的Uint16Array.Float32Array等对象来分配连续的内存空间.看到Uint16Array.Float32Ar ...

  2. ES6之 二进制数组

    ES6之 二进制数组 二进制数组(ArrayBuffer对象. TypedArray 视图和DataView视图)是 JavaScript 操作二进制数据的一个接口.这些对象早就存在,属于独立的规格, ...

  3. 第二十二节,二进制数组

    二进制数组 ArrayBuffer对象 TypedArray视图 复合视图 DataView视图 二进制数组的应用 SharedArrayBuffer 二进制数组(ArrayBuffer对象.Type ...

  4. Dao接口返回数组_JavaScript二进制数组(2)TypedArray视图

    ArrayBuffer对象作为内存区域可以存放多种类型的数据.同一段内存,不同数据有不同的解读方式,这种解读方式称为"视图(view)".ArrayBuffer有两种类型的视图,一 ...

  5. 在定时器中返回给视图的值_JavaScript二进制数组(2)TypedArray视图

    ArrayBuffer对象作为内存区域可以存放多种类型的数据.同一段内存,不同数据有不同的解读方式,这种解读方式称为"视图(view)".ArrayBuffer有两种类型的视图,一 ...

  6. es6 TypedArray视图

    TypedArray视图 ES6 ArrayBuffer对象作为内存区域,可以存放多种类型的数据.同一段内存,不同数据有不同的解读方式,这就叫做"视图"(view).ArrayBu ...

  7. es6二进制数组--基础

    一.概念二进制数组由 ArrayBuffer对象 TypeArray 视图和DataView视图 三部分组成是javascript操作二进制数据的一个接口. 早在2011年2月就已经发布,但是由于ES ...

  8. ECMAScript6(7):二进制数组

    这个部分如果没有C语言和计算机基础会比较难理解,如果实在理解不了可以收藏它,日后再看. 二进制数组其实很早就有了,不过为了 WebGL 中,数据可以高效和显卡交换数据.分为3类: ArrayBuffe ...

  9. JavaScript-二进制与二进制数组

    在ES5中引入了Blob用于处理二进制.在ES6中引入了ArrayBuffer.TypedArray.DataView用于处理二进制数组.常规的前端操作用,用到二进制的地方不多.但是,当我想处理文件的 ...

最新文章

  1. python encoding报错_菜鸟世界 -docker 环境下解决python 的 UnicodeEncodeError 错误
  2. Java动物类enjoy方法打印,面向对象编程题汇总
  3. 计算机网络(十三)-数据链路层-动态分配信道
  4. XOR and Favorite Number(CF-617E)
  5. flexbox算法实现_如何使用Flexbox实现水平滚动
  6. 3D引擎多线程:渲染与逻辑分离
  7. 最近一直因为工作的事情,耽误学习了
  8. Python学习(六)模块
  9. 50预训练权重_MMDetection笔记:修改预训练模型权重类别数
  10. python列表元组字典集合实验心得_python心得 元组,字典,集合
  11. Reed-Solomon Codes——RS纠错码
  12. 下行法求最小割集案例_最小割集求法 -
  13. 分享一个用了很久的免费国外空间,适合用于测试
  14. 虚拟机增加一块新硬盘
  15. Python argparse.ArgumentParser的add_argument()用法
  16. AtCoder - agc005_b(单调栈)
  17. 互动媒体作业一——动态图形临摹
  18. java面试的一些流程问题
  19. win10 系统重装 (官方纯净版,无预置应用)
  20. Windows Service 创建与安装

热门文章

  1. 收藏!企业数据安全防护5条建议
  2. linux无法关机 grub2,Ubuntu关机卡住无法关机如何解决?
  3. python学习list_python学习之list
  4. python3 mysql代码行_教你用100多行写一个数据库(附源码)|python3教程|python入门|python教程...
  5. python 生成器_Python生成器中的GeneratorExit
  6. android 模拟器声音设置,使用android模拟器录制声音
  7. Filezilla 服务器发回了不可路由的地址。使用服务器地址代替
  8. npm ERR! cb() never called!
  9. PLSQL 日期格式修改
  10. docker-compose命令介绍和使用【官方英文文档翻译】【附加案例】