Typed Arrays
Regular JavaScript arrays are flexible: any element can be any type, the length can grow or shrink, and the engine handles the memory for you. That flexibility costs memory and disables a lot of optimisations. Typed arrays are the escape hatch — fixed-size, fixed-element-type buffers of raw binary data. You will not need them for most application code, but the moment you touch a binary protocol, audio sample, image pixel, or WebGL vertex, they become essential.
Two layers: ArrayBuffer and views
The model is two-tier:
An ArrayBuffer is a fixed-length block of raw bytes. You cannot read or write it directly — it is just memory.
A typed array view (like
Uint8Array,Float32Array) is a window onto anArrayBufferthat interprets the bytes as a particular numeric type.Multiple views can share the same buffer — useful for parsing binary formats where one segment is bytes and another is 32-bit integers.
const buf = new ArrayBuffer(16); // 16 raw bytes const bytes = new Uint8Array(buf); // 16 elements: each 0-255 const ints = new Int32Array(buf); // 4 elements: each a 32-bit signed int bytes.length; // 16 ints.length; // 4 (16 bytes / 4 bytes-per-int) bytes[0] = 255; ints[0]; // depends on endianness — see below
The typed array family
Each view enforces a specific element type and size. They all share the same array-like API: length, indexing, forEach, map, set, subarray.
Int8Array/Uint8Array/Uint8ClampedArray— 1 byte per element.Clampedsaturates writes outside 0-255 instead of wrapping.Int16Array/Uint16Array— 2 bytes per element.Int32Array/Uint32Array— 4 bytes per element.Float32Array— 4-byte IEEE-754 single-precision floats.Float64Array— 8-byte IEEE-754 double-precision floats. Same precision as regular JS numbers.BigInt64Array/BigUint64Array— 8 bytes per element, holdBigIntvalues.
Creating typed arrays
// From a length (zero-filled) const a = new Int32Array(5); // Int32Array(5) [0, 0, 0, 0, 0] // From an iterable const b = new Uint8Array([10, 20, 30]); // From another typed array (copies and converts) const c = new Float32Array(b); // Float32Array(3) [10, 20, 30] // From an existing buffer const buf = new ArrayBuffer(8); const d = new Int16Array(buf); // 4 elements const e = new Int16Array(buf, 2, 2); // start at byte 2, take 2 elements
Out-of-range writes — wrap, clamp, truncate
Each view has its own rules for values that do not fit. They never throw — they coerce.
const u8 = new Uint8Array(1); u8[0] = 300; // wraps: 300 % 256 = 44 const u8c = new Uint8ClampedArray(1); u8c[0] = 300; // clamped to 255 u8c[0] = -5; // clamped to 0 const f32 = new Float32Array(1); f32[0] = 0.1 + 0.2; // stored as nearest 32-bit float, loses precision
Endianness with DataView
Typed array views read and write using the host machine's byte order — little-endian on almost every modern CPU. When you are parsing a binary protocol with a fixed byte order, use DataView instead. It lets you specify endianness for every read and write.
const buf = new ArrayBuffer(4); const view = new DataView(buf); view.setUint32(0, 0x01020304, false); // big-endian write new Uint8Array(buf); // [1, 2, 3, 4] view.setUint32(0, 0x01020304, true); // little-endian write new Uint8Array(buf); // [4, 3, 2, 1] view.getUint16(0, true); // read 2 bytes, little-endian
When to actually use typed arrays
Binary protocols — parsing custom file formats, network packets, MIDI data.
WebGL and Canvas — vertex buffers, pixel data (
getImageData().datais aUint8ClampedArray).Web Audio —
AudioBuffer.getChannelData()returns aFloat32Arrayof samples.Crypto —
crypto.subtleandgetRandomValuestake and return typed arrays.WebAssembly — sharing memory between JS and Wasm via
Memory.buffer.Performance-critical numerics — a
Float64Arrayof a million elements uses less memory and is faster to iterate than a regular array of a million numbers.
A small example: parsing a header
Read a 12-byte header
// Imagine a binary header:
// bytes 0-3 : magic number (uint32, big-endian)
// bytes 4-5 : version (uint16, big-endian)
// bytes 6-7 : flags (uint16, big-endian)
// bytes 8-11: payload length (uint32, big-endian)
function parseHeader(buffer) {
const view = new DataView(buffer);
return {
magic: view.getUint32(0, false).toString(16),
version: view.getUint16(4, false),
flags: view.getUint16(6, false),
length: view.getUint32(8, false),
};
}What you still get from regular arrays
Typed arrays have most array methods (map, filter, forEach, reduce, slice) but with one twist: methods that return a new array return a typed array of the same kind. Operations that would change the length (splice, pop) do not exist. If you need a flexible list of numbers, stick with a regular array; reach for a typed array when shape and memory layout actually matter.