Typed Array Views
When a WebAssembly module exports its memory, JavaScript gets a WebAssembly.Memory object. Its .buffer property is a standard ArrayBuffer — the same type used throughout the Web Platform. This means you can overlay any typed-array view on it to read and write memory efficiently.
The ArrayBuffer and typed views
Section titled “The ArrayBuffer and typed views”instance.exports.mem.buffer is an ArrayBuffer. You can construct typed views over it without copying any data:
new Uint8Array(buf)— each element is one unsigned bytenew Int32Array(buf)— each element is four bytes interpreted as a signed 32-bit integernew Float64Array(buf)— each element is eight bytes interpreted as a 64-bit floatnew DataView(buf)— low-level access with explicit methods and endianness control
All of these views share the same underlying memory. Writing through one view is immediately visible through any other view over the same buffer.
Byte offsets and element indices
Section titled “Byte offsets and element indices”Different typed views have different element sizes. The relationship between a typed-array index and a byte offset is:
byte offset = index × element size in bytesFor example, Int32Array has an element size of 4, so i32[2] sits at byte offset 8. Float64Array has an element size of 8, so f64[1] sits at byte offset 8 as well — the same address, different interpretation.
const buf = instance.exports.mem.buffer;const u8 = new Uint8Array(buf);const i32 = new Int32Array(buf);const f64 = new Float64Array(buf);// Write an i32 at byte offset 0 (element index 0 of i32 view)i32[0] = 42;// Read the same 4 bytes as individual bytesconsole.log(u8[0], u8[1], u8[2], u8[3]); // 42 0 0 0Little-endian layout
Section titled “Little-endian layout”WebAssembly memory is little-endian: the least-significant byte of a multi-byte value is stored at the lowest address. For example, the 32-bit value 0x01020304 stored at offset 0 is laid out in memory as bytes [04, 03, 02, 01].
This is consistent with x86/ARM and with JavaScript’s own typed arrays on all current platforms. If you need to handle a specific endianness explicitly, use DataView — its methods like .getInt32(offset, true) accept an isLittleEndian boolean.
Run it
Section titled “Run it”The runner stores two values from Wasm — 0x41424344 at offset 0 and 100 at offset 8 — then reads them back with multiple typed views to show how the same bytes look through different lenses.
Trade-offs
Section titled “Trade-offs”| Option | Benefit | Cost |
|---|---|---|
| Multiple typed-array views over the same buffer | Zero-copy read/write, no copying data between views | Must be recreated every time after memory.grow, since the old ArrayBuffer is detached |
| Interpreting the same bytes as several types directly (manual layout) | Flexible — reach differently-sized fields however you need | No type safety or GC to help — a single wrong offset reads the wrong type immediately |
Common mistakes
Section titled “Common mistakes”- Creating an
Int32ArrayorFloat64Arrayat a byte offset that isn’t aligned to its own element size (e.g. an offset that isn’t a multiple of 4 forInt32Array), which throws in the constructor - Reusing a view created before a
memory.grow, forgetting the oldArrayBufferis detached afterward, so the stale view can no longer be read or written - Forgetting WebAssembly memory is always little-endian, then accidentally calling
DataView.getInt32(offset, false)(big-endian), reading the bytes in the wrong order
💡 Real-world example
Browser-based image editors in the style of Squoosh read the same raw pixel buffer through both a
Uint8ClampedArrayand aFloat32Arrayview depending on the operation, without copying image data between the views.