【lib.es5】ArrayBuffer、DataView 的TypeScript接口

ArrayBuffer、DataView 的 TypeScript 接口
邮箱 :291148484@163.com
CSDN 主页https://blog.csdn.net/qq_28550263?spm=1001.2101.3001.5343
本文地址https://blog.csdn.net/qq_28550263/article/details/123169738

目 录

1. ArrayBuffer

2. DataView


1. ArrayBuffer

ArrayBuffer 对象用来表示通用的、固定长度的原始二进制数据缓冲区。

它是一个字节数组,通常在其他语言中称为“byte array”。

你不能直接操作 ArrayBuffer 的内容,而是要通过类型数组对象或 DataView 对象来操作,它们会将缓冲区中的数据表示为特定的格式,并通过这些格式来读写缓冲区的内容。

1.1 语法

new ArrayBuffer(length)
  • length: 要创建的 ArrayBuffer 的大小,单位为字节。

1.1.1 返回值

一个指定大小的 ArrayBuffer 对象,其内容被初始化为 0。

1.1.2 异常

如果 length 大于 Number.MAX_SAFE_INTEGER(>= 2 ** 53)或为负数,则抛出一个 RangeError 异常。

ArrayBuffer 构造函数用来创建一个指定字节长度的 ArrayBuffer 对象。

1.2 描述

1.2.1 属性

属性 描述
ArrayBuffer.length ArrayBuffer 构造函数的 length 属性,其值为1。
ArrayBuffer.prototype.byteLength 只读属性,表示 ArrayBuffer 的byte的大小,在ArrayBuffer构造完成时生成,不可改变。
get ArrayBuffer[@@species] 返回 ArrayBuffer 的构造函数。
ArrayBuffer.prototype (en-US) 通过 ArrayBuffer 的原型对象可以为所有 ArrayBuffer 对象添加属性。

1.2.2 方法

方法 描述
ArrayBuffer.isView(arg) 如果参数是 ArrayBuffer 的视图实例则返回 true,例如 类型数组对象 或 DataView 对象;否则返回 false。
ArrayBuffer.transfer(oldBuffer [, newByteLength]) (实验性的) 返回一个新的 ArrayBuffer 对象,其内容取自 oldBuffer 中的数据,并且根据 newByteLength 的大小对数据进行截取或补 0。

1.2.3 JavaScript 示例

下面的例子创建了一个 8 字节的缓冲区,并使用一个 Int32Array 来引用它:

var buffer = new ArrayBuffer(8);
var view   = new Int32Array(buffer);

1.2.4 TypeScript 接口

/**
 * 表示二进制数据的原始缓冲区,用于存储不同类型数组的数据。
 * ArrayBuffers不能直接读取或写入,但可以传递给类型化数组或DataView对象,以便根据需要解释原始缓冲区。
 */
interface ArrayBuffer {
    /**
     * 只读。ArrayBuffer的长度(字节)。
     */
    readonly byteLength: number;

    /**
     * 返回ArrayBuffer的一部分。
     */
    slice(begin: number, end?: number): ArrayBuffer;
}

/**
 * ArrayBufferView和相关类型化数组的缓冲区允许的ArrayBuffer类型。
 */
interface ArrayBufferTypes {
    ArrayBuffer: ArrayBuffer;
}
type ArrayBufferLike = ArrayBufferTypes[keyof ArrayBufferTypes];

interface ArrayBufferConstructor {
    readonly prototype: ArrayBuffer;
    new(byteLength: number): ArrayBuffer;
    isView(arg: any): arg is ArrayBufferView;
}
declare var ArrayBuffer: ArrayBufferConstructor;

interface ArrayBufferView {
    /**
     * 数组引用的ArrayBuffer实例。
     */
    buffer: ArrayBufferLike;

    /**
     * 数组的字节长度。
     */
    byteLength: number;

    /**
     * 数组的偏移量,以字节为单位。
     */
    byteOffset: number;
}

2. DataView

DataView 视图是一个可以从 二进制ArrayBuffer 对象中读写多种数值类型的底层接口,使用它时,不用考虑不同平台的字节序问题。

2.1 语法

new DataView(buffer [, byteOffset [, byteLength]])
  • buffer 一个 已经存在的ArrayBuffer 或 SharedArrayBuffer 对象,DataView 对象的数据源。
  • byteOffset 可选,该 DataView 对象的第一个字节在 buffer 中的字节偏移。如果未指定,则默认从第一个字节开始。
  • byteLength 可选,该 DataView 对象的第一个字节在 buffer 中的字节偏移。如果未指定,则默认从第一个字节开始。

返回值
一个表示指定数据缓存区的新DataView 对象。(这句话也许不是非常有助于说明清楚)

你可以把返回的对象想象成一个二进制字节缓存区 array buffer 的“解释器”——它知道如何在读取或写入时正确地转换字节码。这意味着它能在二进制层面处理整数与浮点转化、字节顺序等其他有关的细节问题。

异常
RangeError
如果 byteOffset 或者 byteLength 参数的值导致视图超出了 buffer 的结束位置就会抛出此异常。
例如,假设 buffer (缓冲对象)是 16 字节长度,byteOffset 参数为 8,byteLength 参数为 10,这个错误就会抛出,这是因为结果视图试图超出 buffer 对象的总长度 2 个字节。

2.2 描述

2.2.1 Endianness(字节序)

需要多个字节来表示的数值,在存储时其字节在内存中的相对顺序依据平台架构的不同而不同。

字节序,或字节顺序(“Endian”、“endianness” 或 “byte-order”),描述了计算机如何组织字节,组成对应的数字。
每个内存存储位置都有一个索引或地址。每一 字节可以存储一个8位数字(即 介于0x00 和 0xff 之间)。
因此,你必须保留不止一个字节来储存一个更大的数字。现在,大部分需占用多个字节的数字排序方式是 little-endian(译者注:可称小字节序、低字节序,即低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。

与之对应的 big-endian 排列方式相反,可称大字节序、高字节序),所有的英特尔处理器都使用 little-endian。little-endian 的意思是使用低位储存更重要的信息,least-to-most-significant(最不重要的(least significant)字节取第一个位置,或者说地址最低的位置),可类比欧洲通用的日期书写方式(例如,31 December 2050。译者注:年份是最重要的,月份其次,日期最后)。

自然, big-endian 是相反的顺序, 可类比 ISO 日期格式(例如 2050-12-31)。big-endian 通常被称作"网络字节顺序"(“network byte order”), 因为互联网标准通常要求数据使用 big-endian 存储,从标准 Unix 套接字(socket)层开始,一直到标准化网络的二进制数据结构。此外,老式 Mac 计算机的 68000 系列 和 PowerPC(译者注:IBM 与 Apple 公司联合生产的个人台式机)微处理器曾使用 big-endian。

如:用不同字节序存储数字 0x12345678(即十进制中的 305 419 896):

little-endian:0x78 0x56 0x34 0x12
big-endian:0x12 0x34 0x56 0x78

var littleEndian = (function() {
  var buffer = new ArrayBuffer(2);
  new DataView(buffer).setInt16(0, 256, true /* 设置值时,使用小端字节序 */);
  // Int16Array 使用系统字节序(由此可以判断系统字节序是否为小端字节序)
  return new Int16Array(buffer)[0] === 256;
})();
console.log(littleEndian); // 返回 true 或 false

2.2.2 位整数值

因为 JavaScript 目前不包含对 64 位整数值支持的标准,所以 DataView 不提供原生的 64 位操作。作为变通,您可以实现自己的 getUint64() 函数,以获得精度高达 Number.MAX_SAFE_INTEGER 的值,可以满足某些特定情况的需求。

function getUint64(dataview, byteOffset, littleEndian) {
  // 将 64 位整数值分成两份 32 位整数值
  const left =  dataview.getUint32(byteOffset, littleEndian);
  const right = dataview.getUint32(byteOffset+4, littleEndian);

  // 合并两个 32 位整数值
  const combined = littleEndian? left + 2**32*right : 2**32*left + right;

  if (!Number.isSafeInteger(combined))
    console.warn(combined, 'exceeds MAX_SAFE_INTEGER. Precision may be lost');

  return combined;
}

或者,如果需要填满 64 位,可以创建一个 BigInt。此外,尽管原生 BigInt 要比用户端的库中模拟的 BigInt 快得多,但在 JavaScript 中,BigInt 总是比 32 位整数慢得多,这是因为 BigInt 的大小是可变的。

const BigInt = window.BigInt, bigThirtyTwo = BigInt(32), bigZero = BigInt(0);
function getUint64BigInt(dataview, byteOffset, littleEndian) {
  // 将 64 位整数值分成两份 32 位整数值
  const left = BigInt(dataview.getUint32(byteOffset|0, !!littleEndian)>>>0);
  const right = BigInt(dataview.getUint32((byteOffset|0) + 4|0, !!littleEndian)>>>0);

  // 合并两个 32 位整数值并返回
  return littleEndian ? (right<<bigThirtyTwo)|left : (left<<bigThirtyTwo)|right;
}

2.2.3 构造器、属性与方法

所有 DataView 实例都继承自 DataView.prototype,并且允许向 DataView 对象中添加额外属性。

2.2.3.1 构造器

DataView(): 创建新的DataView对象。

2.2.3.2 实例属性

属性 描述
DataView.prototype.buffer 此视图引用的ArrayBuffer。在构造时固定,因此是只读的。
DataView.prototype.byteLength 此视图从其ArrayBuffer开始的长度(以字节为单位)。在构造时固定,因此是只读的。
DataView.prototype.byteOffset 此视图从其ArrayBuffer开始的偏移量(以字节为单位)。在构造时固定,因此是只读的。

2.2.3.3 实例方法

方法 描述
DataView.prototype.getInt8() 从视图开始处的指定字节偏移量处获取一个有符号的8位整数(字节)。
DataView.prototype.getUint8() 从视图开始处的指定字节偏移量处获取一个无符号8位整数(无符号字节)。
DataView.prototype.getInt16() 从视图开始处的指定字节偏移量处获取一个有符号的16位整数(短整型)。
DataView.prototype.getUint16() 从视图开始处的指定字节偏移量处获取一个无符号16位整数(无符号短整型)。
DataView.prototype.getInt32() 从视图开始处的指定字节偏移量处获取一个有符号的32位整数(长整型)。
DataView.prototype.getUint32() 从视图开始处的指定字节偏移量处获取一个无符号32位整数(无符号长整型)。
DataView.prototype.getFloat32() 从视图开始处的指定字节偏移量处获取一个带符号的32位浮点(float)。
DataView.prototype.getFloat64() 从视图开始处的指定字节偏移量处获取一个带符号的64位浮点型(双精度)。
DataView.prototype.getBigInt64() 从视图开始处的指定字节偏移量处获取一个带符号的64位整数(长整型)。
DataView.prototype.getBigUint64() 从视图开始处的指定字节偏移量处获取一个无符号64位整数(无符号长整型)。
DataView.prototype.setInt8() 在距视图开头的指定字节偏移量处存储一个有符号的8位整数(字节)值。
DataView.prototype.setUint8() 在距视图开头的指定字节偏移量处存储一个无符号8位整数(无符号字节)值。
DataView.prototype.setInt16() 在距视图开始处的指定字节偏移量处存储一个有符号的16位整数(短整型)值。
DataView.prototype.setUint16() 在距视图开头的指定字节偏移量处存储一个无符号16位整数(无符号短整型)值。
DataView.prototype.setInt32() 在距视图开头的指定字节偏移量处存储一个有符号的32位整数(长整型)值。
DataView.prototype.setUint32() 在距视图开头的指定字节偏移量处存储一个无符号32位整数(无符号长整型)值。
DataView.prototype.setFloat32() 在距视图开头的指定字节偏移量处存储一个带符号的32位浮点(float)值。
DataView.prototype.setFloat64() 在距视图开头的指定字节偏移量处存储一个带符号的64位浮点(双精度)值。
DataView.prototype.setBigInt64() 在距视图开头的指定字节偏移量处存储一个带符号的64位整数值(long long)。
DataView.prototype.setBigUint64() 在距视图开头的指定字节偏移量处存储一个无符号64位整数值(无符号长整型)。

2.2.4 JavaScript 示例

var buffer = new ArrayBuffer(16);
var view = new DataView(buffer, 0);

view.setInt16(1, 42);
view.getInt16(1); // 42

2.2.5 TypeScript 接口

interface DataView {
    readonly buffer: ArrayBuffer;
    readonly byteLength: number;
    readonly byteOffset: number;
    /**
     * 获取距视图开头指定字节偏移量处的Float32值。没有对齐约束;多字节值可以从任何偏移量获取。
     * @param byteOffset 缓冲区中应检索值的位置。
     */
    getFloat32(byteOffset: number, littleEndian?: boolean): number;

    /**
     * 从视图的开始处获取指定字节偏移量处的Float64值。没有对齐约束;多字节值可以从任何偏移量获取。
     * @param byteOffset 缓冲区中应检索值的位置。
     */
    getFloat64(byteOffset: number, littleEndian?: boolean): number;

    /**
     * 从视图的开始处获取指定字节偏移量处的Int8值。没有对齐约束;多字节值可以从任何偏移量获取。
     * @param byteOffset 缓冲区中应检索值的位置。
     */
    getInt8(byteOffset: number): number;

    /**
     * 从视图的开始处获取指定字节偏移量处的Int16值。没有对齐约束;多字节值可以从任何偏移量获取。
     * @param byteOffset 缓冲区中应检索值的位置。
     */
    getInt16(byteOffset: number, littleEndian?: boolean): number;
    /**
     * 从视图的开始处获取指定字节偏移量处的Int32值。没有对齐约束;多字节值可以从任何偏移量获取。
     * @param byteOffset 缓冲区中应检索值的位置。
     */
    getInt32(byteOffset: number, littleEndian?: boolean): number;

    /**
     * 从视图的开始处获取指定字节偏移量处的Uint8值。没有对齐约束;多字节值可以从任何偏移量获取。
     * @param byteOffset 缓冲区中应检索值的位置。
     */
    getUint8(byteOffset: number): number;

    /**
     * 从视图的开始处获取指定字节偏移量处的Uint16值。没有对齐约束;多字节值可以从任何偏移量获取。
     * @param byteOffset 缓冲区中应检索值的位置。
     */
    getUint16(byteOffset: number, littleEndian?: boolean): number;

    /**
     * 从视图的开始处获取指定字节偏移量处的Uint32值。没有对齐约束;多字节值可以从任何偏移量获取。
     * @param byteOffset 缓冲区中应检索值的位置。
     */
    getUint32(byteOffset: number, littleEndian?: boolean): number;

    /**
     * 在距视图开头的指定字节偏移量处存储Float32值。
     * @param byteOffset 缓冲区中应该设置值的位置。
     * @param value 要设置的值。
     * @param littleEndian 如果为 false 或 undefined,则应写入大端值,否则应写入小端值。
     */
    setFloat32(byteOffset: number, value: number, littleEndian?: boolean): void;

    /**
     * 在距视图开始处的指定字节偏移量处存储一个Float64值。
     * @param byteOffset 缓冲区中应该设置值的位置。
     * @param value 要设置的值。
     * @param littleEndian 如果为 false 或 undefined,则应写入大端值,否则应写入小端值。
     */
    setFloat64(byteOffset: number, value: number, littleEndian?: boolean): void;

    /**
     * 在距视图开始处的指定字节偏移量处存储一个Int8值。
     * @param byteOffset 缓冲区中应该设置值的位置。
     * @param value 要设置的值。
     */
    setInt8(byteOffset: number, value: number): void;

    /**
     * 在距视图开始处的指定字节偏移量处存储一个Int16值。
     * @param byteOffset 缓冲区中应该设置值的位置。
     * @param value 要设置的值。
     * @param littleEndian 如果为 false 或 undefined,则应写入大端值,否则应写入小端值。
     */
    setInt16(byteOffset: number, value: number, littleEndian?: boolean): void;

    /**
     * 在距视图开始处的指定字节偏移量处存储一个Int32值。
     * @param byteOffset 缓冲区中应该设置值的位置。
     * @param value 要设置的值。
     * @param littleEndian 如果为 false 或 undefined,则应写入大端值,否则应写入小端值。
     */
    setInt32(byteOffset: number, value: number, littleEndian?: boolean): void;

    /**
     * 在距视图开始处的指定字节偏移量处存储一个Uint8值。
     * @param byteOffset 缓冲区中应该设置值的位置。
     * @param value 要设置的值。
     */
    setUint8(byteOffset: number, value: number): void;

    /**
     * 在距视图开头的指定字节偏移量处存储一个Uint16值。
     * @param byteOffset 缓冲区中应该设置值的位置。
     * @param value 要设置的值。
     * @param littleEndian 如果为 false 或 undefined,则应写入大端值,否则应写入小端值。
     */
    setUint16(byteOffset: number, value: number, littleEndian?: boolean): void;

    /**
     * 在距视图开头的指定字节偏移量处存储一个Uint32值。
     * @param byteOffset 缓冲区中应该设置值的位置。
     * @param value 要设置的值。
     * @param littleEndian 如果为 false 或 undefined,则应写入大端值,否则应写入小端值。
     */
    setUint32(byteOffset: number, value: number, littleEndian?: boolean): void;
}
上一篇:Javascript实战——电子钟(时钟、闹钟、计时器、倒计时)


下一篇:2021-03-25