JavaScript-⼆进制与⼆进制数组
在ES5中引⼊了Blob⽤于处理⼆进制。在ES6中引⼊了ArrayBuffer、TypedArray、DataView⽤于处理⼆进制数组。常规的前端操作⽤,⽤到⼆进制的地⽅不多。但是,当我想处理⽂件的传输时候,使⽤⼆进制进⾏传输可以更快。在进⾏异步数据传输(AJAX)时,很可能出现这种场景。
Blob
Blob(Binary Large Object)对象代表了⼀段⼆进制数据,提供了⼀系列操作接⼝。其他操作⼆进制数据的API(⽐如File对象),都是建⽴在Blob对象基础上的,继承了它的属性和⽅法。
⽣成Blob对象有两种⽅法:⼀种是使⽤Blob构造函数,另⼀种是对现有的Blob对象使⽤slice⽅法切出⼀部分。
(1)Blob构造函数,接受两个参数。第⼀个参数是⼀个包含实际数据的数组,第⼆个参数是数据的类型,这两个参数都不是必需的。
var htmlParts = ["<a id=\"a\"><b id=\"b\">hey!<\/b><\/a>"];
var myBlob = new Blob(htmlParts, { "type" : "text\/xml" });
下⾯是⼀个利⽤Blob对象,⽣成可下载⽂件的例⼦。
var blob = new Blob(["Hello Lee"]);
var a = ateElement("a");
a.href = ateObjectURL(blob);
a.download = "";
body.appendChild(a);
上⾯的代码⽣成了⼀个超级链接,点击后提⽰下载⽂本⽂件,⽂件内容为“Hello Lee”。
(2)Blob对象的slice⽅法,将⼆进制数据按照字节分块,返回⼀个新的Blob对象。
var newBlob = oldBlob.slice(startingByte, endindByte);
下⾯是⼀个使⽤XMLHttpRequest对象,将⼤⽂件分割上传的例⼦。
function upload(blobOrFile) {
var xhr = new XMLHttpRequest();
xhr.open('POST', '/server', true);
xhr.send(blobOrFile);
}
document.querySelector('input[type="file"]').addEventListener('change', function(e) {
var blob = this.files[0];
const BYTES_PER_CHUNK = 1024 * 1024; // 1MB chunk sizes.
const SIZE = blob.size;
var start = 0;
var end = BYTES_PER_CHUNK;
while(start < SIZE) {
upload(blob.slice(start, end));
start = end;
end = start + BYTES_PER_CHUNK;
}
}, false);
})();
(3)Blob对象有两个只读属性:
size:⼆进制数据的⼤⼩,单位为字节。
type:⼆进制数据的MIME类型,全部为⼩写,如果类型未知,则该值为空字符串。
在Ajax操作中,如果sponseType设为blob,接收的就是⼆进制数据。
⼆进制数组
(1)ArrayBuffer对象:代表内存之中的⼀段⼆进制数据,可以通过“视图”进⾏操作。“视图”部署了数组接⼝,这意味着,可以⽤数组的⽅法操作内存。
(2) TypedArray对象:⽤来⽣成内存的视图,通过9个构造函数,可以⽣成9种数据格式的视图,⽐如Uint8Array(⽆符号8位整数)数组视图, Int16Array(16位整数)数组视图, Float32Array(32位浮点数)数组视图等等。
(3)DataView对象:⽤来⽣成内存的视图,可以⾃定义格式和字节序,⽐如第⼀个字节是Uint8(⽆符号8位整数)、第⼆个字节是
Int16(16位整数)、第三个字节是Float32(32位浮点数)等等。
简单说,ArrayBuffer对象代表原始的⼆进制数据,TypedArray对象代表确定类型的⼆进制数据,DataView对象代表不确定类型的⼆进制数据。它们⽀持的数据类型⼀共有9种(DataView对象⽀持除Uint8C以外的其他8种)。
ArrayBuffe对象
概述
ArrayBuffer对象代表储存⼆进制数据的⼀段内存,它不能直接读写,只能通过视图(TypedArray视图和DataView视图)来读写,视图的作⽤是以指定格式解读⼆进制数据。
ArrayBuffer也是⼀个构造函数,可以分配⼀段可以存放数据的连续内存区域。
var buf = new ArrayBuffer(32);
上⾯代码⽣成了⼀段32字节的内存区域,每个字节的值默认都是0。可以看到,ArrayBuffer构造函数的参数是所需要的内存⼤⼩(单位字节)。
为了读写这段内容,需要为它指定视图。DataView视图的创建,需要提供ArrayBuffer对象实例作为参数。
var buf = new ArrayBuffer(32);
var dataView = new DataView(buf);
上⾯代码对⼀段32字节的内存,建⽴DataView视图,然后以不带符号的8位整数格式,读取第⼀个元素,结果得到0,因为原始内存的ArrayBuffer对象,默认所有位都是0。
另⼀种TypedArray视图,与DataView视图的⼀个区别是,它不是⼀个构造函数,⽽是⼀组构造函数,代表不同的数据格式。
var buffer = new ArrayBuffer(12);
var x1 = new Int32Array(buffer);
x1[0] = 1;
var x2 = new Uint8Array(buffer);
x2[0]  = 2;
x1[0] // 2
上⾯代码对同⼀段内存,分别建⽴两种视图:32位带符号整数(Int32Array构造函数)和8位不带符号整数(Uint8Array构造函数)。由于两个视图对应的是同⼀段内存,⼀个视图修改底层内存,会影响到另⼀个视图。
TypedArray视图的构造函数,除了接受ArrayBuffer实例作为参数,还可以接受正常数组作为参数,直接分配内存⽣成底层的ArrayBuffer实例,并同时完成对这段内存的赋值。
var typedArray = new Uint8Array([0,1,2]);
typedArray.length // 3
typedArray[0] = 5;
typedArray // [5, 1, 2]
上⾯代码使⽤TypedArray视图的Uint8Array构造函数,新建⼀个不带符号的8位整数视图。可以看到,Uint8Array直接使⽤正常数组作为参数,对底层内存的赋值同时完成。
ArrayBuffer.prototype.byteLength
ArrayBuffer实例的byteLength属性,返回所分配的内存区域的字节长度。
var buffer = new ArrayBuffer(32);
buffer.byteLength
// 32
如果要分配的内存区域很⼤,有可能分配失败(因为没有那么多的连续空余内存),所以有必要检查是否分配成功。
if (buffer.byteLength === n) {
// 成功
} else {
// 失败
}
ArrayBuffer.prototype.slice()
ArrayBuffer实例有⼀个slice⽅法,允许将内存区域的⼀部分,拷贝⽣成⼀个新的ArrayBuffer对象。
var buffer = new ArrayBuffer(8);
var newBuffer = buffer.slice(0, 3);
上⾯代码拷贝buffer对象的前3个字节(从0开始,到第3个字节前⾯结束),⽣成⼀个新的ArrayBuffer对象。slice⽅法其实包含两步,第⼀步是先分配⼀段新内存,第⼆步是将原来那个ArrayBuffer对象拷贝过去。
slice⽅法接受两个参数,第⼀个参数表⽰拷贝开始的字节序号(含该字节),第⼆个参数表⽰拷贝截⽌的字节序号(不含该字节)。如果省略第⼆个参数,则默认到原ArrayBuffer对象的结尾。
除了slice⽅法,ArrayBuffer对象不提供任何直接读写内存的⽅法,只允许在其上⽅建⽴视图,然后通过视图读写。ArrayBuffer.isView()
ArrayBuffer有⼀个静态⽅法isView,返回⼀个布尔值,表⽰参数是否为ArrayBuffer的视图实例。这个⽅法⼤致相当于判断参数,是否为TypedArray实例或DataView实例。
var buffer = new ArrayBuffer(8);
ArrayBuffer.isView(buffer) // false
indexof的用法javascript
var v = new Int32Array(buffer);
ArrayBuffer.isView(v) // true
TypedArray对象
概述
ArrayBuffer对象作为内存区域,可以存放多种类型的数据。同⼀段内存,不同数据有不同的解读⽅式,这就叫做“视图”(view)。ArrayBuffer有两种视图,⼀种是TypedArray视图,另⼀种是DataView视图,两者的区别主要是字节序,前者的数组成员都是同⼀个数据类型,后者的数组成员可以是不同的数据类型。
⽬前,TypedArray对象⼀共提供9种类型的视图,每⼀种视图都是⼀种构造函数。
Int8Array:8位有符号整数,长度1个字节。
Uint8Array:8位⽆符号整数,长度1个字节。
Uint8ClampedArray:8位⽆符号整数,长度1个字节,溢出处理不同。
Int16Array:16位有符号整数,长度2个字节。
Uint16Array:16位⽆符号整数,长度2个字节。
Int32Array:32位有符号整数,长度4个字节。
Uint32Array:32位⽆符号整数,长度4个字节。
Float32Array:32位浮点数,长度4个字节。
Float64Array:64位浮点数,长度8个字节。
这9个构造函数⽣成的对象,统称为TypedArray对象。它们很像正常数组,都有length属性,都能⽤⽅括号运算符([])获取单个元素,所有数组的⽅法,在类型化数组上⾯都能使⽤。两者的差异主要在以下⽅⾯。
TypedArray数组的所有成员,都是同⼀种类型和格式。
TypedArray数组的成员是连续的,不会有空位。
Typed化数组成员的默认值为0。⽐如,new Array(10)返回⼀个正常数组,⾥⾯没有任何成员,只是10个空位;new
Uint8Array(10)返回⼀个类型化数组,⾥⾯10个成员都是0。
TypedArray数组只是⼀层视图,本⾝不储存数据,它的数据都储存在底层的ArrayBuffer对象之中,要获取底层对象必须使⽤buffer属性。
构造函数
TypedArray数组提供9种构造函数,⽤来⽣成相应类型的数组实例。
构造函数有多种⽤法。
(1)TypedArray(buffer, byteOffset=0, length?)
同⼀个ArrayBuffer对象之上,可以根据不同的数据类型,建⽴多个视图。
// 创建⼀个8字节的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);
上⾯代码在⼀段长度为8个字节的内存(b)之上,⽣成了三个视图:v1、v2和v3。
视图的构造函数可以接受三个参数:
第⼀个参数(必需):视图对应的底层ArrayBuffer对象。
第⼆个参数(可选):视图开始的字节序号,默认从0开始。
第三个参数(可选):视图包含的数据个数,默认直到本段内存区域结束。
因此,v1、v2和v3是重叠的:v1[0]是⼀个32位整数,指向字节0~字节3;v2[0]是⼀个8位⽆符号整数,指向字节2;v3[0]是⼀个16位整数,指向字节2~字节3。只要任何⼀个视图对内存有所修改,就会在另外两个视图上反应出来。
注意,byteOffset必须与所要建⽴的数据类型⼀致,否则会报错。
var buffer = new ArrayBuffer(8);
var i16 = new Int16Array(buffer, 1);
// Uncaught RangeError: start offset of Int16Array should be a multiple of 2
上⾯代码中,新⽣成⼀个8个字节的ArrayBuffer对象,然后在这个对象的第⼀个字节,建⽴带符号的16位整数视图,结果报错。因为,带符号的16位整数需要两个字节,所以byteOffset参数必须能够被2整除。
如果想从任意字节开始解读ArrayBuffer对象,必须使⽤DataView视图,因为TypedArray视图只提供9种固定的解读格式。
(2)TypedArray(length)
视图还可以不通过ArrayBuffer对象,直接分配内存⽽⽣成。
var f64a = new Float64Array(8);
f64a[0] = 10;
f64a[1] = 20;
f64a[2] = f64a[0] + f64a[1];
上⾯代码⽣成⼀个8个成员的Float64Array数组(共64字节),然后依次对每个成员赋值。这时,视图构造函数的参数就是成员的个数。可以看到,视图数组的赋值操作与普通数组的操作毫⽆两样。
(3)TypedArray(typedArray)
类型化数组的构造函数,可以接受另⼀个视图实例作为参数。
var typedArray = new Int8Array(new Uint8Array(4));
上⾯代码中,Int8Array构造函数接受⼀个Uint8Array实例作为参数。
注意,此时⽣成的新数组,只是复制了参数数组的值,对应的底层内存是不⼀样的。新数组会开辟⼀段新的内存储存数据,不会在原数组的内存之上建⽴视图。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。