`DataView` in JavaScript

`DataView` in JavaScript

This article explains DataView in JavaScript.

We will explain in detail the basic usage of DataView and specific examples of its use.

YouTube Video

DataView in JavaScript

JavaScript's DataView is a convenient API for manipulating data stored in a buffer (ArrayBuffer) in various formats. This allows for flexible and efficient reading and writing of binary data, playing an important role in network communication, file processing, and interfacing with WebAssembly.

What is DataView?

DataView provides a view layer over an ArrayBuffer object, allowing you to read and write different data types (such as integers, floating-point numbers, and characters) from any byte offset. DataView is similar to TypedArray, but it is characterized by its ability to specify endianness and perform detailed operations on a byte level.

Basic Syntax of DataView

1let buffer = new ArrayBuffer(16);  // Create a 16-byte ArrayBuffer
2let view = new DataView(buffer);    // Manipulate the buffer with a DataView

DataView has a constructor that takes an ArrayBuffer as an argument. In this example, a 16-byte buffer is created, and DataView is used to access that buffer. Using DataView, you can specify different byte sizes and endianness (big-endian or little-endian) when reading from or writing to data stored in a buffer.

Basic Methods of DataView

DataView provides methods for reading and writing values of various data types. They are mainly divided into get methods for data reading and set methods for writing.

The main methods are shown below.

Methods for Reading Values

  • getInt8(byteOffset): Reads a 1-byte signed integer at the specified offset.
  • getUint8(byteOffset): Reads a 1-byte unsigned integer at the specified offset.
  • getInt16(byteOffset, littleEndian): Reads a 2-byte signed integer.
  • getUint16(byteOffset, littleEndian): Reads a 2-byte unsigned integer.
  • getInt32(byteOffset, littleEndian): Reads a 4-byte signed integer.
  • getUint32(byteOffset, littleEndian): Reads a 4-byte unsigned integer.
  • getFloat32(byteOffset, littleEndian): Reads a 4-byte IEEE 754 floating-point number.
  • getFloat64(byteOffset, littleEndian): Reads an 8-byte IEEE 754 floating-point number.

Methods for Writing Values

  • setInt8(byteOffset, value): Writes a 1-byte signed integer.
  • setUint8(byteOffset, value): Writes a 1-byte unsigned integer.
  • setInt16(byteOffset, value, littleEndian): Writes a 2-byte signed integer.
  • setUint16(byteOffset, value, littleEndian): Writes a 2-byte unsigned integer.
  • setInt32(byteOffset, value, littleEndian): Writes a 4-byte signed integer.
  • setUint32(byteOffset, value, littleEndian): Writes a 4-byte unsigned integer.
  • setFloat32(byteOffset, value, littleEndian): Writes a 4-byte IEEE 754 floating-point number.
  • setFloat64(byteOffset, value, littleEndian): Writes an 8-byte IEEE 754 floating-point number.

By using these methods, you can flexibly read and write data stored in an ArrayBuffer.

Example of using DataView

Let's look at an example of manipulating binary data using DataView.

Example 1: Writing and reading a 16-bit integer

1let buffer = new ArrayBuffer(4);  // Create a 4-byte buffer
2let view = new DataView(buffer);
3
4// Write a 2-byte integer value in little-endian format
5view.setInt16(0, 32767, true);  // byteOffset: 0, value: 32767, littleEndian: true
6
7// Read the data in little-endian format
8let value = view.getInt16(0, true);
9console.log(value);  // Output: 32767
  • In this example, the setInt16 method is used to write a 16-bit signed integer in little-endian format, and the getInt16 method reads that value in little-endian.

Example 2: Writing and reading a floating point number

1let buffer = new ArrayBuffer(8);  // Create an 8-byte buffer
2let view = new DataView(buffer);
3
4// Write an 8-byte floating-point number
5view.setFloat64(0, 3.14159, false);  // byteOffset: 0, value: 3.14159, bigEndian: false
6
7// Read the data in big-endian format
8let pi = view.getFloat64(0, false);
9console.log(pi);  // Output: 3.14159
  • In this example, the setFloat64 method is used to write a 64-bit floating-point number in big-endian format, and that value is read with getFloat64.

About Endianness

Let's see an example of reading and writing values in both big-endian and little-endian formats using DataView.

 1// Example: Handling Endianness with DataView in TypeScript
 2// Create an ArrayBuffer of 4 bytes
 3const buffer = new ArrayBuffer(4);
 4const view = new DataView(buffer);
 5
 6// Store the same number (0x12345678) in both endian formats
 7// By default, DataView uses big-endian
 8view.setUint32(0, 0x12345678); // Big-endian
 9console.log("Big-endian (default):");
10console.log(buffer);
11
12// Overwrite the buffer with little-endian
13view.setUint32(0, 0x12345678, true); // Little-endian
14console.log("Little-endian:");
15console.log(buffer);
16
17// Read values back in both endian modes
18const bigEndianValue = view.getUint32(0); // Big-endian read
19const littleEndianValue = view.getUint32(0, true); // Little-endian read
20
21console.log("Read as Big-endian:", bigEndianValue.toString(16));
22console.log("Read as Little-endian:", littleEndianValue.toString(16));

In DataView methods, data is stored in big-endian (byte order from most significant to least significant byte) by default, but little-endian can be specified optionally. Little-endian reverses the byte order (from least significant to most significant byte). It is important to handle data endianness correctly because different systems and network protocols use different endianness.

Difference from TypedArray

Let's look at the differences between DataView and TypedArray.

 1// Example: TypedArray vs DataView
 2
 3// Create a 8-byte buffer
 4const buffer = new ArrayBuffer(8);
 5
 6// --- Using TypedArray (Int32Array) ---
 7const int32View = new Int32Array(buffer);
 8int32View[0] = 42;
 9int32View[1] = 100;
10
11console.log("TypedArray (Int32Array):");
12console.log(int32View); // Int32Array [42, 100]
13
14// --- Using DataView ---
15const dataView = new DataView(buffer);
16
17// Write different types of data at arbitrary byte offsets
18dataView.setInt8(0, 65);         // 1 byte
19dataView.setUint16(1, 500, true); // 2 bytes, little-endian
20dataView.setFloat32(3, 3.14, true); // 4 bytes, little-endian
21
22console.log("\nDataView:");
23console.log("Int8 at 0:", dataView.getInt8(0));      // 65
24console.log("Uint16 at 1:", dataView.getUint16(1, true)); // 500
25console.log("Float32 at 3:", dataView.getFloat32(3, true)); // 3.14
26
27/*
28Output:
29TypedArray (Int32Array):
30Int32Array [42, 100]
31
32DataView:
33Int8 at 0: 65
34Uint16 at 1: 500
35Float32 at 3: 3.140000104904175
36*/

TypedArray also provides buffer operations based on ArrayBuffer, but TypedArray is suitable for operating on contiguous data with a fixed length and format for each data type. On the other hand, DataView can flexibly operate on different data types and also allows control over endianness. Therefore, DataView is suitable for parsing and constructing complex binary data.

Summary

DataView is a powerful API for handling binary data in JavaScript. You can directly access ArrayBuffer to read and write data while considering integers, floating-point numbers, and differences in endianness. It is useful in situations like network communication and file format parsing, and is indispensable when byte-level control is required. By using it together with TypedArray, you can perform more efficient binary data manipulation.

You can follow along with the above article using Visual Studio Code on our YouTube channel. Please also check out the YouTube channel.

YouTube Video