ArrayBuffer
ArrayBuffer is a built-in object that represents a raw binary data buffer. It represents a fixed-length sequence of bytes that can be used to store and manipulate binary data in JavaScript. Unlike regular JavaScript arrays, ArrayBuffer stores raw binary data without any type interpretation.
Creating an ArrayBuffer
Create an ArrayBuffer using the new keyword with the ArrayBuffer constructor:
const buffer = new ArrayBuffer(16);
// ArrayBuffer { byteLength: 16 }
The constructor takes a single parameter:
length: The number of bytes to allocate (must be a non-negative integer)
If the requested byte length exceeds reasonable limits or is negative, a RangeError is thrown:
new ArrayBuffer(-1); // RangeError: Invalid array length
new ArrayBuffer(Infinity); // RangeError: Invalid array length
ArrayBuffer Properties
byteLength
The byteLength property returns the size of the ArrayBuffer in bytes:
const buffer = new ArrayBuffer(64);
buffer.byteLength; // 64
This property is read-only and cannot be changed after the buffer is created.
ArrayBuffer Methods
slice()
Creates a shallow copy of a portion of the buffer into a new ArrayBuffer:
const buffer = new ArrayBuffer(8);
// Fill with some data
const view = new Uint8Array(buffer);
view[0] = 1;
view[1] = 2;
view[2] = 3;
view[3] = 4;
// Slice from byte 1 to 4 (exclusive)
const sliced = buffer.slice(1, 4);
sliced.byteLength; // 3
new Uint8Array(sliced); // Uint8Array [2, 3, 4]
Syntax: buffer.slice(start, end)
start: Start index (inclusive)end: End index (exclusive)
ArrayBuffer.isView()
A static method that returns true if the argument is a view on an ArrayBuffer:
const buffer = new ArrayBuffer(8);
ArrayBuffer.isView(buffer); // false
ArrayBuffer.isView(new Uint8Array(buffer)); // true
ArrayBuffer.isView(new DataView(buffer)); // true
ArrayBuffer.isView(new Int32Array(buffer, 0, 2)); // true
This is useful for type-checking before performing buffer operations.
ArrayBuffer.transfer() (ES2024)
Transfers ownership of an ArrayBuffer’s backing store to a new ArrayBuffer:
const original = new ArrayBuffer(16);
// Fill with some data
new Uint8Array(original).set([1, 2, 3, 4]);
const transferred = ArrayBuffer.transfer(original, 8);
original.byteLength; // 0 (original is detached)
transferred.byteLength; // 8
new Uint8Array(transferred); // Uint8Array [1, 2, 3, 4]
Syntax: ArrayBuffer.transfer(sourceBuffer, newLength)
sourceBuffer: The ArrayBuffer to transfernewLength: The length of the new buffer in bytes
The original buffer becomes detached (byteLength becomes 0). If newLength is greater than the original length, the new bytes are zero-initialized.
ArrayBuffer.transferToFixedLength() (ES2024)
Similar to transfer() but always creates a fixed-length ArrayBuffer:
const resizable = new ArrayBuffer(16, { maxLength: 32 });
new Uint8Array(resizable).set([10, 20, 30]);
const fixed = ArrayBuffer.transferToFixedLength(resizable, 8);
resizable.byteLength; // 0 (detached)
fixed.byteLength; // 8
new Uint8Array(fixed); // Uint8Array [10, 20, 30, 0, 0, 0, 0, 0]
Key difference: transfer() may return a resizable buffer if the source was resizable, while transferToFixedLength() always returns a fixed-length buffer.
Working with ArrayBuffer
ArrayBuffer by itself doesn’t provide a way to read or write data. You need to use typed arrays or DataView to interact with the buffer’s contents.
Using TypedArrays
TypedArrays provide typed views into ArrayBuffer:
const buffer = new ArrayBuffer(16);
// Create different views on the same buffer
const uint8 = new Uint8Array(buffer);
const int32 = new Int32Array(buffer);
const float64 = new Float64Array(buffer);
// Write using one view
uint8[0] = 255;
uint8[1] = 255;
uint8[2] = 0;
uint8[3] = 0;
// Read using another view
int32[0]; // 65280 (0x0000FF in little-endian)
float64[0]; // 2.83...e-319
Different typed arrays interpret the same bytes differently:
Int8Array: 8-bit signed integerUint8Array: 8-bit unsigned integerInt16Array: 16-bit signed integerUint16Array: 16-bit unsigned integerInt32Array: 32-bit signed integerUint32Array: 32-bit unsigned integerFloat32Array: 32-bit floating pointFloat64Array: 64-bit floating point
Using DataView
DataView provides low-level access to read/write different data types at specific offsets:
const buffer = new ArrayBuffer(12);
const dataView = new DataView(buffer);
// Write different types at specific offsets
dataView.setInt8(0, 42);
dataView.setUint16(2, 1000);
dataView.setFloat64(4, 3.14159);
// Read them back
dataView.getInt8(0); // 42
dataView.getUint16(2); // 1000
dataView.getFloat64(4); // 3.14159
DataView is useful when you need to work with mixed data types in a single buffer.
Detached Buffers
An ArrayBuffer can become “detached” when ownership of its backing store is transferred. Once detached, the buffer’s byteLength becomes 0 and no views on it can be used:
const buffer = new ArrayBuffer(8);
const view = new Uint8Array(buffer);
view[0] = 1;
// Detach by transferring
const newBuffer = ArrayBuffer.transfer(buffer, 8);
view[0]; // 0 (view is now detached)
buffer.byteLength; // 0
Sharing Memory Between Workers
ArrayBuffer is the foundation for sharing memory between Web Workers:
// In main thread
const sharedBuffer = new SharedArrayBuffer(1024);
const sharedView = new Int32Array(sharedBuffer);
// Post the buffer to a worker
worker.postMessage({ sharedBuffer }, [sharedBuffer]);
// In worker
self.onmessage = (e) => {
const sharedView = new Int32Array(e.data.sharedBuffer);
// Both threads can now read/write directly
};
Practical Examples
Reading Binary File Data
// Simulating reading a binary header
function readHeader(buffer) {
const view = new DataView(buffer);
return {
magic: view.getUint32(0),
version: view.getUint16(4),
flags: view.getUint16(6),
dataSize: view.getUint32(8)
};
}
const headerBuffer = new ArrayBuffer(12);
const headerView = new DataView(headerBuffer);
headerView.setUint32(0, 0x4A534F4E); // "JSON" in ASCII
headerView.setUint16(4, 1); // version 1
headerView.setUint16(6, 0); // flags
headerView.setUint32(8, 1024); // data size
readHeader(headerBuffer);
// { magic: 1212766542, version: 1, flags: 0, dataSize: 1024 }
Buffer Reuse with Pooling
class BufferPool {
constructor(size = 1024) {
this.size = size;
this.pool = [];
}
acquire() {
if (this.pool.length > 0) {
return this.pool.pop();
}
return new ArrayBuffer(this.size);
}
release(buffer) {
if (buffer.byteLength === this.size) {
this.pool.push(buffer);
}
}
}
const pool = new BufferPool(256);
const buf1 = pool.acquire();
// ... use buf1 ...
pool.release(buf1);
Browser Compatibility
| Method | Support |
|---|---|
| ArrayBuffer | ES6 (all modern browsers) |
| slice() | ES6 |
| isView() | ES6 |
| transfer() | ES2024 (limited) |
| transferToFixedLength() | ES2024 (limited) |
The ES2024 methods have limited browser support at the time of writing.
See Also
- TypedArrays — Typed array views
- DataView — Mixed-type binary data access
- Uint8Array — 8-bit unsigned integer array