推荐答案
JavaScript 中操作二进制数据主要依赖于 ArrayBuffer、TypedArray 和 DataView 这三个核心对象:
ArrayBuffer:表示一个原始的、固定长度的内存区域(缓冲区)。它本身不能直接读写数据,仅作为一块原始内存的容器。你可以把它看作是一块连续的字节数组,但你无法直接通过索引访问。const buffer = new ArrayBuffer(16); // 创建一个16字节的缓冲区 console.log(buffer.byteLength); // 输出:16
TypedArray:是一组视图,允许以特定的数据类型(如Int8Array、Uint16Array、Float32Array等)来读取和写入ArrayBuffer中的数据。它们提供了类型化的数组视图,可以方便地以不同的数据格式解释同一块内存。const buffer = new ArrayBuffer(8); const int32View = new Int32Array(buffer); // 创建一个Int32类型的视图,大小为8/4 = 2 int32View[0] = 10; int32View[1] = -5; console.log(int32View); // 输出:Int32Array [ 10, -5 ] const uint8View = new Uint8Array(buffer); // 创建一个Uint8类型的视图,大小为8/1=8 console.log(uint8View); // 输出:Uint8Array [ 10, 0, 0, 0, 251, 255, 255, 255 ]
DataView:提供了更灵活的、字节级别的读写访问。它允许你指定从ArrayBuffer中读取和写入数据的起始位置和数据类型,这在处理不同类型数据混合排列的二进制数据时非常有用。const buffer = new ArrayBuffer(8); const dataView = new DataView(buffer); dataView.setInt32(0, 1234, true); // 从索引0开始写入一个32位整数,小端字节序 dataView.setFloat64(4, 3.14, false); // 从索引4开始写入一个64位浮点数,大端字节序 console.log(dataView.getInt32(0, true)); // 读取索引0的32位整数,小端字节序 console.log(dataView.getFloat64(4, false)); //读取索引4的64位浮点数,大端字节序
总的来说,ArrayBuffer 提供原始内存,TypedArray 提供类型化的数组视图,而 DataView 提供灵活的字节级访问。这三者协同工作,使得 JavaScript 可以有效地处理二进制数据。
本题详细解读
ArrayBuffer
ArrayBuffer 是一个不可直接操作的原始二进制数据缓冲区。它仅仅是一段连续的内存空间,长度在创建时确定并且不可更改。你不能直接通过类似数组下标的方式来读写 ArrayBuffer 中的内容。
用途:
- 作为其他二进制数据视图的基础。
- 在需要处理原始二进制数据时,先分配一段
ArrayBuffer,然后再通过TypedArray或DataView来操作它。
常用属性和方法:
byteLength: 返回ArrayBuffer的字节长度。slice(begin, end): 创建一个新的ArrayBuffer,包含原ArrayBuffer中指定范围的字节。transfer(newByteLength): 创建一个新的ArrayBuffer,同时将原有 ArrayBuffer 上的数据复制到新数组中,并且可以改变数组的长度
创建 ArrayBuffer:
const buffer = new ArrayBuffer(1024); // 创建一个 1024 字节的 ArrayBuffer
TypedArray
TypedArray 提供了一组类型化的数组视图,允许你以特定的数据类型(如整数、浮点数等)来操作 ArrayBuffer 中的数据。每一个 TypedArray 都对应着一种特定的数据类型,例如:
Int8Array:8 位有符号整数Uint8Array:8 位无符号整数Int16Array:16 位有符号整数Uint16Array:16 位无符号整数Int32Array:32 位有符号整数Uint32Array:32 位无符号整数Float32Array:32 位浮点数Float64Array:64 位浮点数
用途:
- 方便地以特定的数据类型来读写
ArrayBuffer中的数据。 - 在处理需要特定数据类型的二进制数据(例如图像数据、音频数据等)时非常有用。
创建 TypedArray:
const buffer = new ArrayBuffer(16); const int32Array = new Int32Array(buffer); // 创建一个 Int32Array 视图 const float32Array = new Float32Array(buffer); // 创建一个 Float32Array 视图 const uint8Array = new Uint8Array(buffer, 4, 4); //从下标4开始创建长度为4的 Uint8Array 视图 // 还可以通过直接传入长度来创建 TypedArray const typedArray = new Int32Array(8);
用法:
const buffer = new ArrayBuffer(12); const int32Array = new Int32Array(buffer); int32Array[0] = 10; int32Array[1] = -5; int32Array[2] = 100; console.log(int32Array); // 输出:Int32Array [ 10, -5, 100 ]
DataView
DataView 提供了更灵活的、字节级别的读写访问方式。它允许你指定从 ArrayBuffer 中的哪个字节开始,以哪种数据类型来读写数据,并且可以指定字节序(大端或小端)。
用途:
- 在处理不同数据类型混合排列的二进制数据时非常有用。
- 在需要控制字节序时(例如,网络协议中常用的字节序转换)。
- 在需要从
ArrayBuffer的任意位置读取指定长度的数据时。
创建 DataView:
const buffer = new ArrayBuffer(16); const dataView = new DataView(buffer); // 创建一个 DataView const dataView2 = new DataView(buffer,4,8); // 从偏移4的位置开始,创建8个字节的DataView
常用方法:
getInt8(byteOffset)、getUint8(byteOffset)getInt16(byteOffset, littleEndian)、getUint16(byteOffset, littleEndian)getInt32(byteOffset, littleEndian)、getUint32(byteOffset, littleEndian)getFloat32(byteOffset, littleEndian)getFloat64(byteOffset, littleEndian)setInt8(byteOffset, value)、setUint8(byteOffset, value)setInt16(byteOffset, value, littleEndian)、setUint16(byteOffset, value, littleEndian)setInt32(byteOffset, value, littleEndian)、setUint32(byteOffset, value, littleEndian)setFloat32(byteOffset, value, littleEndian)setFloat64(byteOffset, value, littleEndian)
其中,byteOffset 指定字节偏移量,littleEndian 指定是否使用小端字节序(默认为 false,即大端字节序)。
用法:
const buffer = new ArrayBuffer(8); const dataView = new DataView(buffer); dataView.setInt32(0, 1234); // 从索引0开始写入一个32位整数,大端字节序 dataView.setFloat64(4, 3.14, true); // 从索引4开始写入一个64位浮点数,小端字节序 console.log(dataView.getInt32(0)); // 从索引0开始读取32位整数 console.log(dataView.getFloat64(4, true)); // 从索引4开始读取一个64位浮点数,小端字节序