REF · doc 01 of 06 · binary data suite
ArrayBuffer · TypedArray
· DataView
Reference-grade. Every constructor, method, property, and option of the three foundational binary primitives in JavaScript — the layer that everything else (Buffer, Blob, fetch body, streams) is built on. Animated diagrams for the conceptually tricky pieces; full per-method entries for the rest.
~120 entries
12 animated diagrams
browser + Node
§ 01 ──
// Mental model
Three primitives, one clear separation of concerns. ArrayBuffer is opaque storage: a fixed (or resizable) block of bytes you cannot read directly. TypedArray is the indexable lens: it gives you element access in a chosen numeric type, with host byte order. DataView is the surgical lens: it lets you read or write any size at any offset, with the byte order spelled out.
Calling a TypedArray "an array of bytes" is the most common misconception. It is an array of elements, where the element size depends on the type — one byte for Uint8Array, eight bytes for Float64Array, eight bytes for BigUint64Array. The arithmetic linking element count to byte count is the constant BYTES_PER_ELEMENT on every TypedArray class.
The lens analogy is exact, not metaphorical. A TypedArray owns its .buffer reference but does not own the bytes — they live in the ArrayBuffer. Two TypedArrays of different types over the same buffer see the same memory at different element sizes. Writes through one are visible through the other on the next read. This is C union semantics in JavaScript form.
Detachment is the unusual cliff. When an ArrayBuffer is transferred (to a worker, or via transfer()), it is detached at the source: every view over it suddenly throws on access. There is no equivalent in plain C, where transferring a pointer to another thread is silent. JavaScript surfaces it because ownership crossings have to be observable in a single-threaded language.
Resizable buffers, BigInt 64-bit views, and float16 (where supported) round out the modern surface. They share the same three-piece model — container, indexable lens, surgical lens — and never break it.
§ 04 ──
// Reference · every method, every overload
Organized by class. Within each class, entries are alphabetical except where construction comes first. Every entry carries the full template: signature, summary, parameters, returns, throws, description, performance, since, example, gotchas, bridge to C, source, see-also.
An ArrayBuffer represents a contiguous sequence of bytes. The bytes are zero-initialized at construction. The buffer itself is opaque — you cannot index, iterate, or read it directly. To read or write its contents, you must construct a view: a TypedArray (e.g. Uint8Array) or a DataView.
Modern ArrayBuffers can also be resizable by passing { maxByteLength } to the constructor, and can be transferred between contexts (workers, ports), which detaches the source buffer permanently.
new ArrayBuffer(byteLength, options?)
constructor
new ArrayBuffer(byteLength: number, options?: { maxByteLength?: number }): ArrayBuffer
Creates a new ArrayBuffer of the given length, zero-initialized.
- Parameters
-
- byteLength number — The size in bytes. Must be a non-negative integer. Maximum is implementation-defined (typically 2 GiB − 1 on 32-bit V8, larger on 64-bit).
- options.maxByteLength number optional — If provided, the buffer is resizable up to this length. Must be ≥
byteLength.
- Returns
- A new zero-filled
ArrayBuffer of length byteLength.
- Throws
-
- RangeError — if
byteLength is negative or exceeds the implementation limit.
- RangeError — if
maxByteLength < byteLength.
- TypeError — if called without
new.
The newly created buffer is always zero-filled — unlike Node's Buffer.allocUnsafe, there is no fast-but-uninitialized variant for ArrayBuffer itself. For performance-sensitive code that will overwrite every byte, this zero-fill is unavoidable in the spec.
Without maxByteLength, the buffer is fixed-length: its byteLength never changes. With maxByteLength, it is resizable via .resize(n) up to the cap.
perf O(n) zero-fill
since ES2015 · maxByteLength: ES2024
example
const ab = new ArrayBuffer(16);
console.log(ab.byteLength);
// 16
const resizable = new ArrayBuffer(8, { maxByteLength: 1024 });
console.log(resizable.resizable, resizable.maxByteLength);
// true 1024
gotchas
- Calling without
new throws a TypeError — there is no factory form.
- The maximum length is environment-defined and not constant. Don't allocate close to the limit and expect portability.
- Resizable buffers may not be available in older engines; feature-test with
'resizable' in ArrayBuffer.prototype.
bridge to c
calloc(byteLength, 1) — allocate-and-zero. Resizable buffers are conceptually closer to a void* backed by an arena that supports growth up to a cap (similar to a realloc-capable allocation with a fixed reservation).
source
- V8:
src/objects/js-array-buffer.cc — JSArrayBuffer::Setup
- Spec: ECMA-262 §25.1
- Proposal: tc39/proposal-resizablearraybuffer
ArrayBuffer.isView(arg)
static
ArrayBuffer.isView(arg: unknown): boolean
Returns true if arg is a TypedArray or DataView (i.e. a view over some ArrayBuffer).
- Parameters
- arg unknown — any value to test.
- Returns
true if arg is a view (any TypedArray instance or a DataView). false otherwise — including for plain ArrayBuffer instances themselves.
- Throws
- Does not throw.
Useful as a type guard at API boundaries that accept "any binary buffer view." Note carefully: it is false for ArrayBuffers themselves — they are containers, not views. To accept either, combine with instanceof ArrayBuffer.
perf O(1)
since ES2015
example
ArrayBuffer.isView(new Uint8Array(8)); // true
ArrayBuffer.isView(new DataView(new ArrayBuffer(8))); // true
ArrayBuffer.isView(new ArrayBuffer(8)); // false (container, not view)
ArrayBuffer.isView([1, 2, 3]); // false
ArrayBuffer.isView(Buffer.from('a')); // true (Buffer extends Uint8Array)
gotchas
Buffer in Node returns true — it's a Uint8Array subclass.
- Does not return true for plain Arrays or array-like objects, even if they contain numbers.
bridge to c
No direct analogue — in C, "view" vs "container" is conventional rather than runtime-checked. The closest analogy is a struct tag distinguishing "owner" from "borrowed pointer."
source
- V8:
src/builtins/builtins-arraybuffer.cc — ArrayBufferIsView
- Spec: ECMA-262 §25.1.4.1
byteLength: number // getter
The current size of the buffer in bytes.
- Returns
- A non-negative integer — the current byte length. For resizable buffers, this changes when
resize() is called. For detached buffers, this is 0.
- Throws
- Does not throw. (Returns 0 after detach rather than throwing.)
Accessor property defined on ArrayBuffer.prototype. Each access reads the live length. There is no setter — you cannot assign to ab.byteLength = ....
perf O(1) read
since ES2015
example
const ab = new ArrayBuffer(32);
console.log(ab.byteLength); // 32
const r = new ArrayBuffer(8, { maxByteLength: 64 });
r.resize(20);
console.log(r.byteLength); // 20
const t = ab.transfer();
console.log(ab.byteLength); // 0 (ab is now detached)
gotchas
- After detach, returns 0 silently rather than throwing — easy to miss.
- Cached
byteLength values become stale across resize() calls on resizable buffers.
bridge to c
The stored size accompanying the pointer in any "fat pointer" struct (e.g. { void* p; size_t len; }). C lets you forget the size; JS forces you to carry it.
source
- V8:
src/objects/js-array-buffer.h — JSArrayBuffer::byte_length
- Spec: ECMA-262 §25.1.5.1
detached: boolean // getter
True if the buffer has been detached (its contents transferred or invalidated).
- Returns
true after transfer or any operation that detaches the buffer; false otherwise.
- Throws
- Does not throw.
A buffer becomes detached when its bytes are moved to another buffer via transfer(), when it's structured-cloned with transfer in the transfer list, or when WebAssembly's memory.grow invalidates a backing memory.
Once detached, the buffer is dead: byteLength becomes 0, and every TypedArray or DataView over it throws TypeError on access. Use this property to detect that state before attempting reads.
perf O(1)
since ES2024 (Node 21+, Chrome 119+, Firefox 120+, Safari 16.4+)
example
const ab = new ArrayBuffer(16);
console.log(ab.detached); // false
const moved = ab.transfer();
console.log(ab.detached); // true
console.log(moved.detached); // false
new Uint8Array(ab)[0]; // TypeError: detached buffer
gotchas
- Older runtimes lacked this property; legacy code uses
try/catch on view construction as a workaround.
- Detachment is one-way and unrecoverable. There is no "reattach."
bridge to c
Closest analogue: a freed pointer where free() nulled the variable. JS makes this state observable instead of relying on the programmer to remember.
source
- V8:
src/objects/js-array-buffer.h — JSArrayBuffer::was_detached
- Spec: ECMA-262 §25.1.5.3
maxByteLength
property · ro
maxByteLength: number // getter
The upper bound on the buffer's size, set at construction. For non-resizable buffers, equals byteLength.
- Returns
- The maximum byte length the buffer can grow to via
resize().
- Throws
- Does not throw.
For a buffer constructed with new ArrayBuffer(n, { maxByteLength: m }), returns m. For a fixed-length buffer constructed without options, returns byteLength at construction time (and stays there).
Engines may reserve virtual address space up to maxByteLength, so very large values can fail allocation even when byteLength is small.
perf O(1)
since ES2024
example
const fixed = new ArrayBuffer(64);
console.log(fixed.maxByteLength); // 64
const r = new ArrayBuffer(64, { maxByteLength: 4096 });
console.log(r.maxByteLength); // 4096
gotchas
- Very large
maxByteLength values may cause construction to fail with a RangeError on memory-constrained systems even though no bytes have been committed.
bridge to c
Like a memory reservation made via mmap(NULL, max, PROT_NONE, MAP_ANONYMOUS, -1, 0) — address space is reserved but not committed. resize() is analogous to mprotect changing the committed portion.
source
- V8:
src/objects/js-array-buffer.h — JSArrayBuffer::max_byte_length
- Spec: ECMA-262 §25.1.5.5
resizable: boolean // getter
True if this buffer was constructed as resizable (with a maxByteLength option), false otherwise.
- Returns
true iff this buffer can be resized via resize().
- Throws
- Does not throw.
Fixed at construction: a fixed-length buffer cannot become resizable later, and a resizable buffer cannot be made fixed. Use the constructor options at allocation time to choose.
perf O(1)
since ES2024
example
new ArrayBuffer(8).resizable; // false
new ArrayBuffer(8, { maxByteLength: 32 }).resizable; // true
gotchas
- Use as a feature test for the resizable-buffer proposal:
'resizable' in ArrayBuffer.prototype.
bridge to c
A boolean flag stored in the buffer header — no different from any tagged-union discriminator in C.
source
- V8:
src/objects/js-array-buffer.h — JSArrayBuffer::is_resizable_by_js
- Spec: ECMA-262 §25.1.5.4
resize(newByteLength)
instance
resize(newByteLength: number): undefined
Changes the buffer's length to newByteLength. Only valid on resizable buffers.
- Parameters
- newByteLength number — desired new length. Must be ≥ 0 and ≤
maxByteLength.
- Returns
undefined.
- Throws
-
- TypeError — if the buffer is not resizable.
- RangeError — if
newByteLength is negative or exceeds maxByteLength.
Growing: bytes added at the end are zero-initialized. Shrinking: bytes beyond the new length are no longer accessible. The buffer's identity does not change — views constructed without a length argument (length-tracking views) update their length to match; views with explicit lengths may become out-of-bounds.
perf O(delta) grow; O(1) shrink
since ES2024
example
const ab = new ArrayBuffer(8, { maxByteLength: 64 });
const tracker = new Uint8Array(ab); // length-tracking
const fixed = new Uint8Array(ab, 0, 8); // fixed length
ab.resize(16);
console.log(tracker.length); // 16 — auto-tracked
console.log(fixed.length); // 8 — unchanged
ab.resize(4);
console.log(fixed.length); // 8 — but reads throw (out-of-bounds)
gotchas
- Resizing past
maxByteLength throws RangeError, not silent truncation.
- Fixed-length views that no longer fit don't error on resize — they become out-of-bounds and throw on next access.
- Don't cache
byteLength across resize() calls.
bridge to c
Approximate analogue: realloc(p, newSize) — except that the buffer's identity stays stable in JS (the same ArrayBuffer object), whereas realloc may return a different pointer. This is enabled by V8 reserving address space up front.
source
- V8:
src/builtins/builtins-arraybuffer.cc — ArrayBufferPrototypeResize
- Spec: ECMA-262 §25.1.5.7
slice(begin?, end?)
instance
slice(begin?: number, end?: number): ArrayBuffer
Returns a new ArrayBuffer containing a copy of the bytes from begin (inclusive) to end (exclusive).
- Parameters
-
- begin number optional — start byte (inclusive). Defaults to 0. Negative counts from the end.
- end number optional — end byte (exclusive). Defaults to
byteLength. Negative counts from the end.
- Returns
- A new
ArrayBuffer of length end - begin containing a copy of those bytes. Independent backing memory.
- Throws
- TypeError — if called on a detached buffer.
Important: this is a copy, not a view. The returned buffer has its own bytes — mutating it does not affect the original, and vice versa. For a zero-copy windowed view, construct a TypedArray with explicit byteOffset and length instead.
Out-of-range indices are clamped to [0, byteLength] rather than throwing. If end < begin, the result has length 0.
perf O(n) — allocates + copies
since ES2015
example
const ab = new ArrayBuffer(16);
new Uint8Array(ab).set([1,2,3,4,5,6,7,8]);
const part = ab.slice(2, 5);
console.log(part.byteLength); // 3
console.log(new Uint8Array(part)); // Uint8Array(3) [3, 4, 5]
// independence — mutate part, original unchanged
new Uint8Array(part)[0] = 99;
console.log(new Uint8Array(ab)[2]); // 3 — not affected
ab.slice(-4).byteLength; // 4 — last 4 bytes
gotchas
- Allocates fresh memory — not zero-copy. For hot paths, prefer constructing a TypedArray view with byteOffset/length.
- Different semantics from
TypedArray.prototype.slice (also a copy) and TypedArray.prototype.subarray (a view).
bridge to c
void* part = malloc(end - begin); memcpy(part, src + begin, end - begin); — explicit allocation and copy.
source
- V8:
src/builtins/builtins-arraybuffer.cc — ArrayBufferPrototypeSlice
- Spec: ECMA-262 §25.1.5.6
transfer(newByteLength?)
instance
transfer(newByteLength?: number): ArrayBuffer
Move the buffer's bytes into a new ArrayBuffer and detach the original. Optionally resize during the move.
- Parameters
- newByteLength number optional — desired length of the new buffer. Defaults to current
byteLength. Extra bytes (when growing) are zero-filled; bytes beyond (when shrinking) are dropped.
- Returns
- A new
ArrayBuffer with the same bytes (resized if requested). The new buffer is resizable if the original was; its maxByteLength equals the original's. The original buffer becomes detached.
- Throws
-
- TypeError — if the original is already detached.
- RangeError — if
newByteLength exceeds maxByteLength.
Detach-and-move semantics. The new buffer is a fresh ArrayBuffer object; the original is dead immediately after the call. Any TypedArray or DataView over the original throws TypeError on access afterward.
Engines may implement this as a pointer hand-off rather than a byte copy — making it O(1) for large buffers. (No spec guarantee, but the typical optimization.)
perf O(1) typical (pointer transfer)
since ES2024 (Node 21+, Chrome 119+, Firefox 122+)
example
const ab = new ArrayBuffer(16);
new Uint8Array(ab)[0] = 0xFF;
const moved = ab.transfer();
console.log(moved.byteLength); // 16
console.log(new Uint8Array(moved)[0]); // 0xFF — bytes preserved
console.log(ab.detached); // true
console.log(ab.byteLength); // 0
// resize during transfer
const grown = moved.transfer(32);
console.log(grown.byteLength); // 32 (extra bytes are zero)
gotchas
- Every existing view over the source buffer becomes invalid the instant
transfer() returns.
- For cross-worker structured-clone interop, prefer
structuredClone(value, { transfer: [...] }) — accomplishes the same detach in a more familiar idiom.
- The new buffer's
resizable/maxByteLength mirror the source — to "freeze" length, use transferToFixedLength.
bridge to c
Closer to a move constructor than a copy: ownership of the byte storage shifts to the new buffer object; the old object is invalidated. C has no language-level moves — moves there are conventions on top of memcpy + nulling the source.
source
- V8:
src/builtins/builtins-arraybuffer.cc — ArrayBufferPrototypeTransfer
- Spec: ECMA-262 §25.1.5.8
transferToFixedLength(newByteLength?)
instance
transferToFixedLength(newByteLength?: number): ArrayBuffer
Like transfer, but the new buffer is always non-resizable, regardless of the source.
- Parameters
- newByteLength number optional — same as
transfer.
- Returns
- A new fixed-length
ArrayBuffer. The original is detached.
- Throws
- Same as
transfer.
Use when you want to "lock down" a resizable buffer's size before handing it to a consumer who shouldn't see further size changes. Engines may compact the backing memory since no headroom is reserved.
perf O(1) typical
since ES2024
example
const r = new ArrayBuffer(16, { maxByteLength: 1024 });
const locked = r.transferToFixedLength();
console.log(locked.resizable); // false
console.log(locked.byteLength); // 16
console.log(r.detached); // true
gotchas
- If you don't need to lock the size, prefer
transfer — it preserves the resizable property which is usually what callers expect.
bridge to c
Equivalent to transfer followed by "drop the reservation, only commit the live size" — analogous to remapping at the actual size.
source
- V8:
src/builtins/builtins-arraybuffer.cc — ArrayBufferPrototypeTransferToFixedLength
- Spec: ECMA-262 §25.1.5.9
ArrayBuffer[Symbol.species]
static · legacy
get ArrayBuffer[Symbol.species]: typeof ArrayBuffer
Returns the constructor to be used for derived buffers. By default, returns ArrayBuffer itself.
- Returns
- By default, the
ArrayBuffer constructor.
- Throws
- Does not throw.
Part of the Symbol.species protocol — historically used to let subclasses of ArrayBuffer control which constructor slice uses. The pattern has fallen out of favor; many built-ins (Array, RegExp, Promise) have removed species hooks for performance reasons. Current TC39 direction is to not consult species; you may see this property exist but be effectively dead in modern engines.
perf O(1)
since ES2015 (deprecated direction since 2022)
example
console.log(ArrayBuffer[Symbol.species] === ArrayBuffer); // true
// Subclassing override (legacy pattern):
class TaggedAB extends ArrayBuffer {
static get [Symbol.species]() { return ArrayBuffer; }
}
gotchas
- Don't rely on this for cross-engine behavior — TC39 has been removing species consultation.
- Override only if you specifically need a subclass and accept the perf cost; usually compose instead.
bridge to c
No analogue — this is a JS-specific subclassing hook.
source
- Spec: ECMA-262 §25.1.4.2
- TC39: discussion on species removal
ArrayBuffer.prototype[Symbol.toStringTag]
property
[Symbol.toStringTag]: string // "ArrayBuffer"
The tag used by Object.prototype.toString to produce "[object ArrayBuffer]".
- Returns
- The literal string
"ArrayBuffer".
- Throws
- Does not throw.
Allows generic code to brand-check an ArrayBuffer via the standard Object.prototype.toString.call(x) idiom, returning "[object ArrayBuffer]".
perf O(1)
since ES2015
example
Object.prototype.toString.call(new ArrayBuffer(0)); // "[object ArrayBuffer]"
ArrayBuffer.prototype[Symbol.toStringTag]; // "ArrayBuffer"
gotchas
- Cheaper than
instanceof across realms (e.g. iframes), where each window has its own ArrayBuffer constructor.
bridge to c
Analogous to a struct's tag field for run-time type identification — a poor man's RTTI.
source
- Spec: ECMA-262 §25.1.5.10
Full reference coming in the next turn — every method on the base, including: at, byteLength, byteOffset, BYTES_PER_ELEMENT, copyWithin, entries, every, fill, filter, find, findIndex, findLast, findLastIndex, forEach, includes, indexOf, join, keys, lastIndexOf, length, map, of, reduce, reduceRight, reverse, set, slice, some, sort, subarray, toLocaleString, toReversed, toSorted, toString, values, with, Symbol.iterator, Symbol.toStringTag.
CLASSES
Concrete TypedArrays · 12 of them
Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float16Array, Float32Array, Float64Array, BigInt64Array, BigUint64Array.
Full per-class entries coming in the next turn — each with its constructors (length, iterable, buffer+offset+length), BYTES_PER_ELEMENT, value-range notes, encoding behavior (especially Uint8ClampedArray's saturation and the BigInt arrays' BigInt-only values), and bridge to the corresponding C type.