An ArrayBuffer holds raw bytes for typed arrays and DataView. Sometimes you need to hand those bytes to a new buffer or change their length without keeping two independent owners. JavaScript's ArrayBuffer.prototype.transfer() creates a replacement buffer containing the bytes and detaches the original. After the transfer, use the returned buffer; do not keep using the old one.
This method is available in modern JavaScript environments. It is useful for binary-data pipelines, but it is different from simply copying bytes into another array.
Transfer an ArrayBuffer
Call buffer.transfer() to keep the current byte length, or pass a new byte length. If the new length is larger, JavaScript fills the added bytes with zeros. If it is smaller, it discards bytes from the end. The original buffer's byteLength becomes 0.
Example: Move and resize a buffer
// Transfer bytes and give up ownership of the original buffer.
const original = new ArrayBuffer(4);
new Uint8Array(original).set([10, 20, 30, 40]);
const moved = original.transfer(6);
console.log('Old length:', original.byteLength);
console.log('New length:', moved.byteLength);
console.log('Bytes:', Array.from(new Uint8Array(moved)));
// A shorter target keeps only the first bytes.
const shortened = moved.transfer(3);
console.log('Shortened:', Array.from(new Uint8Array(shortened)));
The output is:
Old length: 0
New length: 6
Bytes: [ 10, 20, 30, 40, 0, 0 ]
Shortened: [ 10, 20, 30 ]
The exact spacing around the printed arrays can vary by console, but the byte values do not. The first transfer expands four bytes to six. The second transfer keeps only the first three bytes and detaches moved in turn.
Why the original is detached
Transfer changes ownership. Any typed-array view that referenced the old buffer becomes unusable for normal data access after detachment. Save the returned buffer and create a new view over it. This prevents code from accidentally continuing to mutate the previous storage.
Example: Replace a typed-array view
const buffer = new ArrayBuffer(2);
const oldView = new Uint8Array(buffer);
oldView.set([7, 9]);
// Transfer ownership, then build a view of the replacement.
const replacement = buffer.transfer();
const newView = new Uint8Array(replacement);
console.log(buffer.byteLength); // 0
console.log(Array.from(newView)); // [7, 9]
Do not rely on oldView after the move. Different operations on a detached view can return empty results or throw; creating a fresh view is the clear, safe approach.
Transfer or copy?
Use slice() when you need a copy and want the source buffer to remain available. Use transfer() when the source should no longer be used. The engine may optimize a transfer without copying every byte, but your code must not depend on any particular performance strategy.
Example: Keep the source with slice()
const source = new ArrayBuffer(3);
new Uint8Array(source).set([1, 2, 3]);
// slice() copies; source remains attached.
const copy = source.slice(0);
console.log(source.byteLength, copy.byteLength); // 3 3
For a resizable ArrayBuffer, transfer() preserves resizability. If you specifically need a fixed-length result, use transferToFixedLength() instead. This distinction matters when another part of your program assumes the result cannot grow or shrink.
Check support and avoid mistakes
Before using the method in an older runtime, check that typeof ArrayBuffer.prototype.transfer === 'function'. If it is unavailable, do not silently replace it with slice() and claim the same ownership behavior: slice() leaves the original attached. Pick a fallback that matches what your application actually needs.
- Store the return value immediately; the old buffer is detached.
- Create new typed-array or
DataViewobjects over the returned buffer. - Use a nonnegative integer byte length within your environment's limits.
- Do not confuse
ArrayBufferwithSharedArrayBuffer; this instance method belongs toArrayBuffer.
Conclusion
ArrayBuffer.prototype.transfer() returns a new owner for the same byte content and detaches the old buffer. Supply a length to grow with zero-filled bytes or truncate from the end. Choose transfer for ownership changes and slice() for an independent copy, then update every view that uses the buffer.