jsguides

DataView

DataView is a built-in JavaScript global object that gives you typed, low-level access to binary data in an ArrayBuffer or SharedArrayBuffer. Unlike typed arrays, DataView gives you explicit control over byte ordering (endianness) and requires no alignment — you can read a 32-bit integer starting at any byte offset.

This makes DataView the right tool when parsing structured binary formats, reading network protocol headers, or interfacing with WebAssembly memory. The tradeoff is verbosity: you have to specify the byte offset and endianness on every read and write, which typed arrays handle automatically.

Constructor

The DataView constructor creates a view onto an existing buffer. You can restrict the view to a portion of the buffer by specifying an offset and length.

new DataView(buffer)
new DataView(buffer, byteOffset)
new DataView(buffer, byteOffset, byteLength)

The first parameter is the underlying buffer. The optional second parameter specifies where the view starts (defaults to byte 0). The optional third parameter specifies how many bytes to expose (defaults to the rest of the buffer).

DataView throws in two situations you need to watch for. Calling it without new throws a TypeError. Passing an offset and length that exceed the buffer’s size throws a RangeError.

const buffer = new ArrayBuffer(8);

// Valid — full buffer view
const view = new DataView(buffer);

// Valid — partial view starting at byte 2
const partial = new DataView(buffer, 2);

// Valid — 4 bytes starting at byte 2
const limited = new DataView(buffer, 2, 4);

// Throws TypeError — missing new keyword
DataView(buffer);

// Throws RangeError — offset + length exceeds buffer
new DataView(buffer, 6, 4);

Properties

DataView exposes three read-only properties that describe the view’s geometry within the buffer.

The buffer property returns the underlying ArrayBuffer or SharedArrayBuffer. This is a reference to the original buffer object, not a copy. Multiple DataView instances can share the same buffer, and changes made through one view are immediately visible through another.

const buffer = new ArrayBuffer(16);
const view = new DataView(buffer, 4, 8);

view.buffer === buffer;  // true — same buffer object
view.byteOffset;         // 4 — view starts at byte 4
view.byteLength;         // 8 — 8 bytes accessible

The byteOffset property tells you where the view starts relative to the beginning of the underlying buffer. The byteLength property tells you how many bytes are accessible through this view. Neither property is writable after construction. The next example demonstrates the default behaviour when byteLength is omitted from the constructor — it automatically spans from the offset to the end of the buffer.

const buffer = new ArrayBuffer(16);
const view = new DataView(buffer, 4);

view.byteOffset; // 4
view.byteLength; // 12 (16 - 4, the default when no length is given)

Getter Methods

DataView provides getters for all integer and floating-point types. Every getter takes a byte offset as its first argument. Multi-byte getters (Int16, Uint16, Int32, Uint32, Float32, Float64, BigInt64, BigUint64, Float16) accept an optional littleEndian flag as their second argument.

By default DataView assumes big-endian byte order. This trips up most developers because most modern platforms are little-endian. When reading common binary formats like PNG, JPEG, WebAssembly, or x86 memory, you almost always want to pass littleEndian: true.

Integer getters

The 8-bit getters read single bytes. They don’t need an endianness flag since a byte only has one byte.

const buffer = new ArrayBuffer(16);
const view = new DataView(buffer);

view.setInt8(0, -10);
view.setUint8(1, 200);

view.getInt8(0);   // -10 — signed 8-bit, range -128 to 127
view.getUint8(1);  // 200 — unsigned 8-bit, range 0 to 255

The 16-bit and 32-bit getters read multi-byte integers. Always specify the endianness explicitly — DataView defaults to big-endian, which is wrong for most platforms. The 16-bit signed range is -32768 to 32767, and the unsigned 16-bit goes up to 65535. For 32-bit integers you get the full -2^31 to 2^31-1 signed range, and up to 2^32-1 unsigned.

const buffer = new ArrayBuffer(16);
const view = new DataView(buffer);

view.setInt16(2, -1000, true);    // little-endian
view.setUint16(4, 60000, true);   // little-endian
view.setInt32(6, -2000000000, true);
view.setUint32(10, 4000000000, true);

view.getInt16(2, true);    // -1000
view.getUint16(4, true);   // 60000
view.getInt32(6, true);    // -2000000000
view.getUint32(10, true);  // 4000000000

BigInt getters

For values that exceed 32-bit limits, use the BigInt variants. These read 64-bit integers and require BigInt syntax (the n suffix) in JavaScript. BigInt getters are useful when dealing with file sizes, high-precision timestamps, or hash values that exceed Number.MAX_SAFE_INTEGER.

const buffer = new ArrayBuffer(32);
const view = new DataView(buffer);

view.setBigInt64(0, 9007199254740993n, true);      // exceeds safe integer limit
view.setBigUint64(8, 18446744073709551615n, true); // max unsigned 64-bit

view.getBigInt64(0, true);   // 9007199254740993n
view.getBigUint64(8, true);  // 18446744073709551615n

Float getters

Float32 reads 4 bytes in IEEE 754 single precision. Float64 reads 8 bytes in double precision. Floating-point getters are essential when binary data encodes measurements, coordinates, or other fractional values — unlike integers, they store decimal numbers directly without manual scaling.

const buffer = new ArrayBuffer(32);
const view = new DataView(buffer);

view.setFloat32(0, 3.402823466e38, true);           // max float32
view.setFloat64(4, 1.7976931348623157e308, true);   // max float64

view.getFloat32(0, true);  // 3.402823466e38
view.getFloat64(4, true); // 1.7976931348623157e308

Float16 (half precision) was added in ES2024. It uses a 2-byte IEEE 754 format with reduced precision — suitable for graphics and machine learning workloads where memory efficiency outweighs numerical accuracy. Not all environments support it yet, so always check for availability before relying on these methods. Reading or writing Float16 on an unsupported runtime throws a TypeError.

// ES2024 only — check support before using
view.setFloat16(0, 1.0, true);
view.getFloat16(0, true); // 1

The getter and setter methods above give you full read access to the buffer. Now let’s look at the corresponding write operations, which follow exactly the same byte offset and endianness conventions.

Setter Methods

Setters mirror getters. Pass the byte offset, then the value. Multi-byte setters accept littleEndian as a third argument. The setter signatures are otherwise identical to their getter counterparts, so if you know the getter API you already know the setter API as well.

const buffer = new ArrayBuffer(16);
const view = new DataView(buffer);

// 8-bit values — no endianness needed
view.setInt8(0, -1);
view.setUint8(1, 255);

// 16-bit values — little-endian
view.setInt16(2, 1000, true);
view.setUint16(4, 60000, true);

// 32-bit values — little-endian
view.setInt32(6, -500, true);
view.setUint32(10, 3000000000, true);

// 64-bit BigInt values
view.setBigInt64(14, 12345678901234n, true);

Setters throw if you write past the view’s bounds. A RangeError means the view doesn’t have enough bytes at that offset.

Endianness

Endianness describes the byte order used to represent multi-byte values. Big-endian stores the most significant byte first; little-endian stores the least significant byte first. Most consumer hardware (x86, ARM on mobile) is little-endian. Network protocols and file formats vary.

DataView defaults to big-endian. That means if you don’t pass true as the second argument to getInt32, setFloat64, etc., it treats the bytes as big-endian. Most of the time this is wrong.

const buffer = new ArrayBuffer(4);
const view = new DataView(buffer);

// Write the same 32-bit value two ways
view.setUint32(0, 0x01020304, false);  // big-endian
view.setUint32(0, 0x01020304, true);   // little-endian

// Reading back with the wrong endianness gives a completely different number
view.getUint32(0, false);  // 16909060 (0x01020304 as big-endian)
view.getUint32(0, true);   // 67305985 (0x04030201 as little-endian)

You can detect your platform’s endianness by writing a known value with DataView and reading it back with a typed array (which uses platform endianness). This trick exploits the fact that typed arrays always use the platform’s native byte order, while DataView lets you specify it explicitly.

function isLittleEndian() {
  const buffer = new ArrayBuffer(2);
  new DataView(buffer).setInt16(0, 1, true);  // write 1 as little-endian via DataView
  return new Int16Array(buffer)[0] === 1;     // read back via typed array
}

isLittleEndian(); // true on most modern hardware

Common Pitfalls

Out-of-bounds access. Every DataView has a fixed byte range. Reading or writing past byteOffset + byteLength throws a RangeError. Validate your offsets before accessing. This is the most common mistake when working with partial views — the constructor may accept a smaller range than the full buffer.

const buffer = new ArrayBuffer(8);
const view = new DataView(buffer, 0, 4);  // only 4 bytes accessible (0 to 3)

view.getInt32(0, true);   // OK — bytes 0-3 are valid
view.getInt32(4, true);   // RangeError — bytes 4-7 are out of bounds for this view

Forgetting new. DataView must always be called with new. Calling it as a plain function throws a TypeError.

Wrong endianness. If your numbers look wrong (especially with binary formats like PNG or WebAssembly), check whether you passed the endianness flag. The default big-endian is rarely what you want for common formats.

Float16 immaturity. The getFloat16() and setFloat16() methods require ES2024. They will throw in Node.js versions before 20 and in older browsers. Always check typeof DataView.prototype.getFloat16 !== 'undefined' before using them.

Practical Examples

Reading a binary header

When you receive a file or network response as an ArrayBuffer, you can use DataView to parse the structure. This example reads a 12-byte header with four fields.

// 12-byte header: magic (4 bytes), version (2 bytes), flags (2 bytes), size (4 bytes)
const buffer = getHeaderBuffer();  // ArrayBuffer from fetch response or file read
const view = new DataView(buffer);

const magic = view.getUint32(0, false);   // big-endian magic number
const version = view.getUint16(4, false);  // big-endian version field
const flags = view.getUint16(6, false);   // big-endian flags
const size = view.getUint32(8, false);     // big-endian payload size

if (magic !== 0x4A534F4E) {
  throw new Error('Invalid header');
}

Reading WebAssembly memory

WebAssembly memory is always little-endian. DataView is the correct interface for reading values from WASM memory because it gives you explicit control over byte order, which typed arrays handle implicitly. The following example writes and reads a 64-bit integer and a 32-bit float in a WASM memory buffer.

const memory = new WebAssembly.Memory({ initial: 1 });
const view = new DataView(memory.buffer);

// Write a 64-bit value at byte offset 0
view.setBigUint64(0, 12345678901234n, true);

// Read it back
view.getBigUint64(0, true); // 12345678901234n

// Write and read a 32-bit float at offset 8
view.setFloat32(8, 2.5, true);
view.getFloat32(8, true); // 2.5

Mixed-type buffer access

DataView handles buffers that contain heterogeneous data — a uint16 ID, a float32 score, and a 12-byte string packed together. This is where DataView really shines: typed arrays force a uniform element size, but DataView lets you treat every byte offset as a different type.

const buffer = new ArrayBuffer(20);
const view = new DataView(buffer);

// Pack heterogeneous data: id (u16), score (f32), name[12 chars]
view.setUint16(0, 42, true);
view.setFloat32(2, 98.6, true);

for (let i = 0; i < 12; i++) {
  view.setUint8(6 + i, 'H'.charCodeAt(0) + i);
}

// Read it back
view.getUint16(0, true);                         // 42
view.getFloat32(2, true);                       // 98.6
String.fromCharCode(...new Uint8Array(buffer, 6, 12));  // "HIJKLMNOPQRST"

See Also

  • ArrayBuffer — The underlying buffer type that DataView reads from
  • TypedArray — Typed array views with fixed element sizes but platform-dependent endianness