jsguides

TypedArray

A TypedArray describes a view of an ArrayBuffer that allows reading and writing binary data in specific formats. Instead of storing arbitrary JavaScript values, typed arrays store elements as raw binary numbers, making them much more efficient for numerical operations.

Creating a TypedArray

TypedArrays require an ArrayBuffer as their backing store:

// Create an 8-byte buffer
const buffer = new ArrayBuffer(8);

// Create an Int32Array view into the buffer
const int32View = new Int32Array(buffer);
// 4 integers (8 bytes / 4 bytes per int32)

const uint8View = new Uint8Array(buffer);
// 8 bytes (8 bytes / 1 byte per uint8)

When you create a typed array with an explicit ArrayBuffer, you control exactly how many bytes to allocate and which view type to use. Multiple views of different types can share the same buffer, which is the key benefit — you can read the same memory as 32-bit integers in one view and as individual bytes in another, without copying data.

You can also create a TypedArray directly with a length:

const float64 = new Float64Array(4);
// Creates a 32-byte buffer (4 × 8 bytes)
// Contains 4 elements, all initially 0

Creating a typed array with a length is shorthand that allocates a new ArrayBuffer automatically. This is the most common pattern when you know how many elements you need upfront. Keep in mind that all elements are initialized to 0, unlike regular arrays which start empty.

TypedArray types

Different typed arrays handle different number types:

TypeSizeRange
Int8Array1 byte-128 to 127
Uint8Array1 byte0 to 255
Int16Array2 bytes-32,768 to 32,767
Uint16Array2 bytes0 to 65,535
Int32Array4 bytes-2,147,483,648 to 2,147,483,647
Uint32Array4 bytes0 to 4,294,967,295
Float32Array4 bytes1.2e-38 to 3.4e38
Float64Array8 bytes5e-324 to 1.8e308
Uint8ClampedArray1 byte0 to 255 (clamped)

The Uint8ClampedArray is special — values outside 0-255 are clamped rather than wrapping:

const clamped = new Uint8ClampedArray(2);
clamped[0] = 200;
clamped[1] = 300;  // Becomes 255, not 44
clamped           // Uint8ClampedArray [200, 255]

Uint8ClampedArray is used most often with the Canvas API for pixel data. When you set a pixel channel value to 300, the clamped array quietly caps it at 255 instead of wrapping modulo 256 as a regular Uint8Array would. This avoids surprising color artifacts in image processing.

Accessing and modifying elements

Access elements using bracket notation:

const buffer = new ArrayBuffer(4);
const view = new Int16Array(buffer);

view[0] = 1000;
view[1] = -500;

view[0]   // 1000
view[1]   // -500
view[2]   // 0 (uninitialized)

Typed arrays use standard bracket notation just like regular arrays, with one key difference: accessing an out-of-bounds index returns undefined in regular arrays but undefined (converted to 0 on assignment) in typed arrays. Also, setting a value outside the element type’s range wraps around — for example, assigning 256 to a Uint8Array element stores 0.

The shared buffer means changes in one view affect others:

const buffer = new ArrayBuffer(4);
const int16 = new Int16Array(buffer);
const uint8 = new Uint8Array(buffer);

int16[0] = 0x0102;  // 258 in decimal
uint8[0]   // 2 (low byte)
uint8[1]   // 1 (high byte)

This example demonstrates endianness in practice. On a little-endian system (x86, most ARM), the least significant byte comes first, so writing 0x0102 to an Int16 view results in byte 0 being 0x02 and byte 1 being 0x01. The byte-level view lets you inspect exactly how multi-byte values are laid out in memory.

Properties and methods

TypedArrays share many methods with regular arrays:

const nums = new Int8Array([1, 2, 3, 4, 5]);

nums.length              // 5
nums.byteLength          // 5 (bytes)
nums.buffer              // The underlying ArrayBuffer
nums.entries()           // Iterator of [index, value]
nums.keys()              // Iterator of indices
nums.values()            // Iterator of values

nums.slice(1, 3)         // New Int8Array [2, 3]
nums.set([10, 20], 1)    // Now [1, 10, 20, 4, 5]
nums.subarray(1, 3)      // View into [10, 20]

Note the difference between slice() and subarray(): slice() creates a new typed array backed by a new buffer (a copy), while subarray() returns a new view over the same buffer. Use slice() when you want independent data and subarray() when you want a zero-copy window into existing memory.

Practical examples

Reading binary file headers

// Imagine reading an 8-byte header
const headerBytes = new Uint8Array([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]);

// Read as big-endian 32-bit values
const dataView = new DataView(headerBytes.buffer);
const magic = dataView.getUint32(0, false);  // false = big-endian
// 0x89504E47 (PNG magic number)

A DataView provides endianness-aware access to an ArrayBuffer, which is essential for parsing binary formats (PNG, MP4, WAV) where multi-byte fields have a defined byte order. Unlike typed arrays, DataView lets you choose big-endian or little-endian per call, so you don’t depend on the host platform’s native order.

Image pixel manipulation

// A tiny 2x2 RGBA image (16 bytes)
const rgba = new Uint8ClampedArray([
  255, 0, 0, 255,     // Red
  0, 255, 0, 255,     // Green
  0, 0, 255, 255,     // Blue
  255, 255, 0, 255    // Yellow
]);

// Calculate average red value
let totalRed = 0;
for (let i = 0; i < rgba.length; i += 4) {
  totalRed += rgba[i];
}
const avgRed = totalRed / 4;
// 63

Canvas pixel data is always RGBA with Uint8ClampedArray, so pixels are laid out as four consecutive bytes per pixel. The stride (4) is the same for all RGBA images regardless of dimensions, which makes row-by-row or pixel-by-pixel iteration straightforward.

Audio sample processing

// 16-bit mono audio samples
const samples = new Int16Array(1000);

// Normalize by finding peak
let peak = 0;
for (let i = 0; i < samples.length; i++) {
  peak = Math.max(peak, Math.abs(samples[i]));
}

const scale = 32767 / peak;
// Scale all samples to use full range
for (let i = 0; i < samples.length; i++) {
  samples[i] = samples[i] * scale;
}

Audio samples from the Web Audio API arrive as Float32Array values in the range [-1, 1], but when working with 16-bit PCM data (WAV files, raw recordings), Int16Array is the correct type. Normalizing 16-bit samples scales them to use the full dynamic range, which is critical for clean-sounding audio output.

Endianness

TypedArrays use the platform’s native byte order by default. Use DataView for explicit control:

const buffer = new ArrayBuffer(4);
const typed = new Uint32Array(buffer);
const view = new DataView(buffer);

typed[0] = 1;
// On little-endian: bytes are [1, 0, 0, 0]
// On big-endian: bytes are [0, 0, 0, 1]

view.getUint32(0, true)   // 1 (little-endian)
view.getUint32(0, false)  // 16777216 (big-endian)

Endianness is invisible when reading and writing through a single typed array view, but it matters as soon as you share the buffer with byte-level views or send data across systems. DataView removes the guesswork by accepting an explicit boolean for byte order on every read and write.

TypedArray vs regular Array

TypedArrays and regular Arrays share many methods — map(), filter(), slice(), forEach(), find(), reduce() — but they differ in important ways. TypedArrays have a fixed length set at creation time; you cannot push or pop elements. All values are stored as the numeric type of the array (writing a float to an Int32Array truncates it to an integer). TypedArrays do not have holes — every index holds an actual number, initialized to 0. This makes them predictable and significantly faster than regular arrays for numeric computation, especially in tight loops.

Shared memory with multiple views

Multiple TypedArray views can point to the same ArrayBuffer. A change through one view is immediately visible in all others, because they are all reading from the same underlying memory:

const buf = new ArrayBuffer(4);
const bytes = new Uint8Array(buf);
const ints = new Int32Array(buf);

ints[0] = 1;
bytes[0]; // 1 (on a little-endian system)

This sharing is what makes typed arrays efficient — you can interpret the same block of memory as different types without copying it.

Use cases

TypedArrays are the right choice when working with WebGL (vertex and index buffers), the Web Audio API (sample data), WebSockets or fetch (binary protocols), File API (reading binary files), and SharedArrayBuffer for multi-threaded shared memory. For general-purpose data processing with JavaScript values (objects, strings, mixed types), a regular array is simpler. TypedArrays are a precision tool for binary data, not a general-purpose performance optimization.

See also

  • BigInt — Arbitrary-precision integers
  • Symbol — Unique primitive values
  • Error — Error objects for exception handling