zoukankan      html  css  js  c++  java
  • es6二进制数组--基础

    一、概念
    二进制数组由 ArrayBuffer对象 TypeArray 视图和DataView视图 三部分组成是javascript操作二进制数据的一个接口。
    早在2011年2月就已经发布,但是由于ES6 的出现,将这些对象添加了一些新的方法。它是一种类似C语言中直接操作字节的机制。

    产生背景
    这个接口的原始设计目的,与WebGL项目有关。所谓WebGL,就是指浏览器与显卡之间的通信接口,为了满足JavaScript与显卡之间大量的、
    实时的数据交换,它们之间的数据通信必须是二进制的,而不能是传统的文本格式。文本格式传递一个32位整数,两端的JavaScript脚本与显卡都要进行格式转化,将非常耗时。
    这时要是存在一种机制,可以像C语言那样,直接操作字节,将4个字节的32位整数,以二进制形式原封不动地送入显卡,脚本的性能就会大幅提升。

    它很像C语言的数组,允许开发者以数组下标的形式,直接操作内存,大大增强了JavaScript处理二进制数据的能力,使得开发者有可能通过JavaScript与操作系统的原生接口进行二进制通信。

    二、ArrayBuffer对象:代表原始的二进制数据。可以通过
    TypeArray 进行操作,即可以操作内存

      它不能直接读写,只能通过(TypedArrayDataView)来读写。

      ArrayBuffer也是一个构造函数,可以分配一段可以存放数据的连续内存区域。

      例如我想生成一段32字节的内存区域,每个字节的值默认都是0,就可以这样创建:

      

      var buffer32 = new ArrayBuffer(32);
      var buffer = new ArrayBuffer();
      console.log(buf);
      


    如上图所示:
    ArrayBuffer 的实力上 有一个 byteLength的属性,原型上有一个slice方法,还有共有方法 isView 下面我们来给大家一一解读

    byteLength:是ArrayBuffer实例的属性,返回所分配的内存区域的字节长度。
    buffer32.byteLength == 32 true 

    需要注意的是:如果你想分配一块比较大的内存区域,需要检查是否分配成功,因为可能没有那么多的连续空余内存。
    if(buffer.byteLength === n){
        //成功
    }else{
        //失败
    }

     slice:有两个参数,第一个参数表示开始拷贝的字节序号(包含此字节),第二个参数表示截止拷贝的字节序号(不含此字节),如果省略第二个参数,则默认截止到原ArrayBuffer对象的结尾。

     slice:是ArrayBuffer实例的一个方法,允许将内存区域的一部分,拷贝生成一个新的ArrayBuffer对象。

    var buffer = new ArrayBuffer(8);
    var newBuffer = buffer.slice(0, 3);
    console.log(buffer); // { byteLength: 8 }
    console.log(newBuffer);//{ byteLength: 3 }

    ArrayBuffer.isView()

    isView:是ArrayBuffer的一个静态方法,返回一个布尔值,表示参数是否为ArrayBuffer的视图实例。这个方法大致相当于判断参数,是否为TypedArray实例或DataView实例。

    var buffer = new ArrayBuffer(8);
    ArrayBuffer.isView(buffer) // false
    
    var v = new Int32Array(buffer);
    ArrayBuffer.isView(v) // true
    
    

    三. TypedArray 视图

    
    

    TypedArray数组只提供9种固定的构造函数,用来生成相应类型的数组实例。

    
    

    (1)TypedArray(buffer, byteOffset=0, length?)

    
    

    视图的构造函数可以接受三个参数:

    
    
    • 第一个参数(必需):视图对应的底层ArrayBuffer对象。

    • 第二个参数(可选):视图开始的字节序号,默认从0开始。

    • 第三个参数(可选):视图包含的数据个数,默认直到本段内存区域结束。

    
    
     
    
    
    // 创建一个8字节的ArrayBuffer
    var b = new ArrayBuffer(8);
    
    // 创建一个指向b的Int32视图,开始于字节0,直到缓冲区的末尾
    var v1 = new Int32Array(b); // [0, 0] 不是很理解
    
    // 创建一个指向b的Uint8视图,开始于字节2,直到缓冲区的末尾
    var v2 = new Uint8Array(b, 2);//[0, 0, 0, 0, 0, 0]
    
    // 创建一个指向b的Int16视图,开始于字节2,长度为2
    var v3 = new Int16Array(b, 2, 2);//[0, 0]
    
    

    v1[0]是一个32位整数,指向字节0~字节3;v2[0]是一个8位无符号整数,指向字节2;v3[0]是一个16位整数,指向字节2~字节3。只要任何一个视图对内存有所修改,就会在另外两个视图上反应出来。

    
    

    注:byteOffset必须与所要建立的数据类型一致,比如:带符号的16位整数需要两个字节,所以byteOffset参数必须能够被2整除

    (2)TypedArray(length)

    视图还可以不通过ArrayBuffer对象,直接分配内存而生成。

    var f64a = new Float64Array(8); //64字节
    f64a[0] = 10;
    f64a[1] = 20;
    f64a[2] = f64a[0] + f64a[1]; // 30

    (3)TypedArray(typedArray)

    TypedArray数组的构造函数,可以接受另一个TypedArray实例作为参数。

    var typedArray = new Int8Array(new Uint8Array(4));

    注:新数组会开辟一段新的内存存数据。

     
    var x = new Int8Array([1, 1]);
    var y = new Int8Array(x);
    x[0] // 1
    y[0] // 1
    
    x[0] = 2;
    y[0] // 1
    
    //基于同一段内存
    var x = new Int8Array([1, 1]);
    var y = new Int8Array(x.buffer);
    x[0] // 1
    y[0] // 1
    
    x[0] = 2;
    y[0] // 2


    (4)TypedArray(arrayLikeObject)

    //普通数组生成TypedArray实例
    var typedArray = new Uint8Array([1, 2, 3, 4]);
    //这时TypedArray视图会重新开辟内存,不会在原数组的内存上建立视图
    
    
    //TypedArray数组转换回普通数组
    var normalArray = Array.prototype.slice.call(typedArray);

    需要注意的是:TypedArray数组除了没有concat方法之外,拥有普通数组所有的操作方法和属性

    如果想要合并多个TypedArray数组,可以用下面这个函数。

    function concatenate(resultConstructor, ...arrays) {
      let totalLength = 0;
      for (let arr of arrays) {
        totalLength += arr.length;
      }
      let result = new resultConstructor(totalLength);
      let offset = 0;
      for (let arr of arrays) {
        result.set(arr, offset);
        offset += arr.length;
      }
      return result;
    }
    
    concatenate(Uint8Array, Uint8Array.of(1, 2), Uint8Array.of(3, 4))
    // Uint8Array [1, 2, 3, 4]

    TypedArray数组也可以被遍历。

     
    let ui8 = Uint8Array.of(0, 1, 2);
    for (let byte of ui8) {
      console.log(byte);
    }
    // 0
    // 1
    // 2
    
    

    ArrayBuffer 与字符串的互相转换

    
    

    注:字符串的编码方法是确定的,才可以相互转换。

    
    
    // ArrayBuffer转为字符串,参数为ArrayBuffer对象
    function ab2str(buf) {
      return String.fromCharCode.apply(null, new Uint16Array(buf));
    }
    
    // 字符串转为ArrayBuffer对象,参数为字符串
    function str2ab(str) {
      var buf = new ArrayBuffer(str.length * 2); // 每个字符占用2个字节
      var bufView = new Uint16Array(buf);
      for (var i = 0, strLen = str.length; i < strLen; i++) {
        bufView[i] = str.charCodeAt(i);
      }
      return buf;
    }
    
    

    TypedArray.prototype.buffer:返回整段内存区域对应的ArrayBuffer对象,属性为只读。

    
    

    TypedArray.prototype.byteLength:返回TypedArray数组占据的内存长度,单位为字节,属性为只读。

    
    

    TypedArray.prototype.byteOffset:返回TypedArray数组从底层ArrayBuffer对象的哪个字节开始,属性为只读。

    
    

    TypedArray.prototype.length:TypedArray数组含有多少个成员。

    
    

    TypedArray.prototype.set():用于复制数组(普通数组或TypedArray数组)。

    
    

    TypedArray.prototype.subarray():对于TypedArray数组的一部分,再建立一个新的视图。

    
    

    TypedArray.prototype.slice():返回一个指定位置的新的TypedArray实例。

    
    

    TypedArray.of():用于将参数转为一个TypedArray实例。

    
    

    TypedArray.from():返回一个基于这个结构的TypedArray实例。

    
    

    3. 复合视图

    
    
    var buffer = new ArrayBuffer(24);
    
    var idView = new Uint32Array(buffer, 0, 1);
    var usernameView = new Uint8Array(buffer, 4, 16);
    var amountDueView = new Float32Array(buffer, 20, 1);
    
    

    上面代码将一个24字节长度的ArrayBuffer对象,分成三个部分:

    
    
    • 字节0到字节3:1个32位无符号整数

    • 字节4到字节19:16个8位整数

    • 字节20到字节23:1个32位浮点数

    
    

    4. DataView视图

    
    

    DataView实例有以下属性,含义与TypedArray实例的同名方法相同。

    
    
    • DataView.prototype.buffer:返回对应的ArrayBuffer对象

    • DataView.prototype.byteLength:返回占据的内存字节长度

    • DataView.prototype.byteOffset:返回当前视图从对应的ArrayBuffer对象的哪个字节开始

    
    

    DataView实例提供8个方法读取内存。

    
    
    • getInt8:读取1个字节,返回一个8位整数。

    • getUint8:读取1个字节,返回一个无符号的8位整数。

    • getInt16:读取2个字节,返回一个16位整数。

    • getUint16:读取2个字节,返回一个无符号的16位整数。

    • getInt32:读取4个字节,返回一个32位整数。

    • getUint32:读取4个字节,返回一个无符号的32位整数。

    • getFloat32:读取4个字节,返回一个32位浮点数。

    • getFloat64:读取8个字节,返回一个64位浮点数。

    
    

    DataView视图提供8个方法写入内存。

    
    
    • setInt8:写入1个字节的8位整数。

    • setUint8:写入1个字节的8位无符号整数。

    • setInt16:写入2个字节的16位整数。

    • setUint16:写入2个字节的16位无符号整数。

    • setInt32:写入4个字节的32位整数。

    • setUint32:写入4个字节的32位无符号整数。

    • setFloat32:写入4个字节的32位浮点数。

    • setFloat64:写入8个字节的64位浮点数。

     


     



     
    
    
  • 相关阅读:
    测试
    vue项目中使用 SheetJS / js-xlsx 导入文件
    vue项目中使用 SheetJS / js-xlsx 导出文件
    vue项目中使用canvas
    uniapp中mqtt的基本使用
    uniapp中vuex的基本使用
    uniapp如何在当前页面获取上个页面的变量、方法
    “微信小程序从分享卡片进入,第一次获取不到用户uid、第二次能获取到用户uid”解决方法
    vue-router的安装和使用
    vue-cli的安装步骤
  • 原文地址:https://www.cnblogs.com/qinmengjiao123-123/p/7194169.html
Copyright © 2011-2022 走看看