JavaScript ArrayBuffer, Binary Arrays
JavaScript, a language foundational to modern web development, provides a diverse set of tools and constructs for handling various data types. One of the more
Most of the time JavaScript works with text and JSON, but the moment you touch files, images, audio, WebSockets, or fetch responses you are dealing with raw bytes. JavaScript handles those bytes through ArrayBuffer and a family of typed array views. This chapter explains what each piece is, how they relate, and when to reach for them — with runnable examples you can verify yourself.
The mental model is two layers:
ArrayBuffer— a fixed-length block of raw memory. It is just bytes; you cannot read or write it directly.- Views (typed arrays and
DataView) — objects that interpret those bytes as numbers. You always read and write through a view.
What is an ArrayBuffer?
An ArrayBuffer is a generic, fixed-length container of raw binary data — a chunk of memory measured in bytes. It has no notion of "elements" or types; it only knows how many bytes it holds. Its size is set at creation and cannot change.
To actually do something with those bytes, you wrap the buffer in a view.
Typed arrays: views over a buffer
A typed array is a view that interprets the buffer as an array of numbers of a fixed type. Indexing, iterating, and arithmetic work just like a normal array, but the data lives in the buffer's raw memory, which makes typed arrays compact and fast for large numeric datasets.
The view type decides how many bytes each element takes:
| View | Bytes per element | Value range |
|---|---|---|
Uint8Array | 1 | 0 … 255 |
Int8Array | 1 | -128 … 127 |
Uint16Array | 2 | 0 … 65535 |
Int16Array | 2 | -32768 … 32767 |
Uint32Array | 4 | 0 … 4294967295 |
Int32Array | 4 | -2³¹ … 2³¹-1 |
Float32Array | 4 | 32-bit float |
Float64Array | 8 | 64-bit float |
Uint8ClampedArray | 1 | 0 … 255 (clamped) |
Creating typed arrays
You can build a typed array from a length, from an existing array, or over an existing buffer.
Several views can share one buffer
This is the key idea: multiple views can sit on the same buffer. Writing through one view changes the bytes, and every other view immediately sees the change. That is how you reinterpret the same bytes in different ways.
Overflow and clamping
Each element is fixed-width, so out-of-range values wrap around (they are taken modulo the type's size). Uint8ClampedArray is the exception — it clamps to 0…255 instead, which is exactly what canvas pixel data needs.
Slicing and sub-views
slice() copies into a brand-new buffer, while subarray() returns another view over the same memory — cheaper, but writes are shared.
DataView: mixed types and endianness
A typed array forces one type and uses the platform's native byte order. DataView is the low-level alternative: it lets you read and write different types at any byte offset, and lets you choose the byte order (endianness) explicitly. That control is essential when parsing file formats and network protocols, where the byte order is fixed by a specification rather than by your CPU.
Endianness is the order in which a multi-byte number is stored: big-endian puts the most significant byte first, little-endian puts it last. Each get/set method on DataView takes a littleEndian flag (default is big-endian).
Here is the same 32-bit number written in both byte orders so you can see the difference:
Converting between bytes and other types
Binary data rarely lives alone — you constantly move between buffers, strings, and higher-level objects.
Bytes ↔ text
To turn a string into bytes (and back), use TextEncoder / TextDecoder, which encode as UTF-8. See TextDecoder and TextEncoder for the full API.
Getting at the underlying buffer
Every typed array exposes its buffer, plus byteOffset and byteLength describing the region it covers. This is how you hand bytes to an API that wants an ArrayBuffer.
Where binary arrays are actually used
- Files. Reading a file as an
ArrayBufferlets you inspect headers, parse formats, or upload raw bytes. See Blob and the File API. - Network.
fetch(...).arrayBuffer()and WebSocket binary frames give you anArrayBufferto decode. - Canvas.
ctx.getImageData().datais aUint8ClampedArrayof RGBA pixel bytes you can read and rewrite. - WebGL / Web Audio. Vertex buffers and audio samples are typed arrays for performance.
Example: read a file as an ArrayBuffer
In the browser, FileReader (or the newer Blob.arrayBuffer()) reads file contents into a buffer that you then parse with a DataView or typed array. For a fuller walkthrough see the File API.
function readBinaryFile(file) {
const reader = new FileReader();
reader.onload = () => {
const view = new DataView(reader.result);
console.log(view.getUint8(0)); // first byte, e.g. a format signature
};
reader.readAsArrayBuffer(file);
}
// Modern alternative:
// const buffer = await file.arrayBuffer();Best practices
- Pick the smallest type that fits.
Uint8Arrayfor byte streams,Float64Arrayfor precise math — using a wider type than needed wastes memory. - Use
DataViewonly when you need mixed types or a fixed endianness. For a uniform numeric array, a typed array is simpler and faster. - Reuse buffers in hot loops to reduce allocation and garbage-collection churn.
- Remember views share memory — use
slice()when you need an independent copy,subarray()when you intentionally want to alias.
Summary
- An
ArrayBufferis raw, fixed-length memory; you never touch it directly. - Typed arrays view that memory as numbers of one fixed type and behave like arrays.
DataViewreads and writes mixed types at arbitrary offsets with explicit endianness — ideal for parsing protocols and file formats.- Views over the same buffer share memory, so a write through one is visible through all.
- These types power files, network responses, canvas pixels, audio, and WebGL.