推荐答案
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位浮点数,小端字节序