JavaScript - TypedArray & DataView
Overview
Estimated time: 35–45 minutes
Typed arrays provide efficient views over raw binary buffers for numbers and bytes. Use DataView for mixed-typed layouts and manual endianness control. Learn to encode/decode text and manipulate binary structures safely.
Learning Objectives
- Create
ArrayBuffer
and view it withTypedArray
types. - Use
DataView
to read/write different numeric types with chosen endianness. - Convert between strings and bytes with
TextEncoder
/TextDecoder
. - Slice, copy, and share data between views correctly.
Prerequisites
- JavaScript - Numbers & BigInt
- JavaScript - JSON (recommended)
ArrayBuffer and TypedArray
ArrayBuffer
is a fixed-length raw binary buffer. Typed arrays are views that interpret bytes as specific numeric types.
// Create a 16-byte buffer and 32-bit integer view over it
const buf = new ArrayBuffer(16);
const u32 = new Uint32Array(buf); // 16 / 4 = 4 elements
u32[0] = 0x11223344;
u32[1] = 0xAABBCCDD;
// Another view on the same bytes
const u8 = new Uint8Array(buf); // 16 bytes
u8[0]; // first byte of the buffer (endianness affects how u32 maps to bytes)
// Copying vs sharing
const clone = u8.slice(); // copy (new buffer)
const view2 = new Uint8Array(buf, 4, 4); // view into bytes [4,8)
DataView for mixed types and endianness
DataView
lets you read/write different numeric types at byte offsets and choose little/big endian per access.
const dv = new DataView(buf);
// Write values (little-endian true)
dv.setUint16(0, 0xABCD, true); // bytes 0..1
dv.setInt32(2, -42, true); // bytes 2..5
// Read values
dv.getUint16(0, true); // 43981 (0xABCD)
dv.getInt32(2, true); // -42
From/To plain arrays and views
// Initialize from array (copies data)
const f32 = new Float32Array([1.0, 2.5, -3.75]);
// Copy between views
const out = new Uint8Array(6);
out.set(new Uint8Array(f32.buffer, 0, 6)); // copy first 6 bytes
// Subarray is a view window (no copy)
const window = f32.subarray(1); // shares buffer
Text encoding and decoding
// Encode JS string into UTF-8 bytes
const enc = new TextEncoder();
const bytes = enc.encode('Hello, 🌍'); // Uint8Array
// Decode UTF-8 bytes back to string
const dec = new TextDecoder('utf-8');
dec.decode(bytes); // 'Hello, 🌍'
Struct example
Define a simple binary record layout: u16 id, i8 flags, f32 value (little-endian).
function writeRecord(dv, offset, { id, flags, value }) {
dv.setUint16(offset, id, true); // 2 bytes
dv.setInt8(offset + 2, flags); // 1 byte
dv.setFloat32(offset + 3, value, true); // 4 bytes
return offset + 7;
}
function readRecord(dv, offset) {
const id = dv.getUint16(offset, true);
const flags = dv.getInt8(offset + 2);
const value = dv.getFloat32(offset + 3, true);
return { id, flags, value };
}
const buf2 = new ArrayBuffer(14);
const dv2 = new DataView(buf2);
writeRecord(dv2, 0, { id: 513, flags: -1, value: Math.PI });
writeRecord(dv2, 7, { id: 1024, flags: 3, value: -2.5 });
readRecord(dv2, 0); // { id: 513, flags: -1, value: 3.14159... }
readRecord(dv2, 7); // { id: 1024, flags: 3, value: -2.5 }
Common Pitfalls
- Endianness: Typed arrays use platform endianness for multi-byte values;
DataView
lets you specify endian per access. - Bounds: Out-of-bounds reads/writes throw RangeError; ensure offsets and lengths are valid.
- Sharing: Multiple views over the same buffer share bytes—mutations are visible across views.
- Immutability: ArrayBuffer length is fixed; to grow, allocate a new buffer and copy or use
resizeable
ArrayBuffer in modern environments if available.
Try it
Run to write/read mixed types and encode/decode text: