Typed Arrays in ECMAScript

What are they?

Typed arrays provide a way to quickly and easily manipulate the raw data stored inside a binary data buffer. This is really useful for processing audio and video data. They're similar to arrays, but with some subtle differences we'll cover in the How are they different from normal arrays? section.

How do they work?

To get an understanding of typed arrays, let's look at the following areas:

  1. Numeric data types - a way of representing the data stored in an array buffer
  2. Array Buffers – where the data is stored
  3. Data Views – reading and writing the data in a typed array

Numeric data types

Numbers are stored in a 64-bit floating point format in JavaScript, which isn't particularly efficient if you only need to represent an 8-bit integer (you're wasting 56 bits!).

Numeric types give us the ability to allocate only the memory we need, which makes mathematical operations on the data a lot more speedy. For example, if you use an int8 typed array, then each element in the array will take up 8 bits.

The following 8 numeric types are available:

  1. int8
  2. uint8
  3. int16
  4. uint16
  5. int32
  6. uint32
  7. float32
  8. float64

Array Buffers

An array buffer is an object that represents the raw binary data of the typed array. Their contents can't be manipulated directly, so to do so you'll need to make use of a data view.

let arrayBuffer = new ArrayBuffer(5); // allocates 5 bytes for this buffer

Data Views

Data views are the means by which the data stored in an array buffer can be accessed and manipulated.

There are type specific views for each of the different numeric types and also a generic DataView object.

let arrayBuffer = new ArrayBuffer(10); // allocates 10 bytes for this buffer

// creates a generic Data View object with access to all 10 bytes
let dataView = new DataView(arrayBuffer);

dataView.setInt8(0, 5); // stores the number 5 in the first byte
dataView.getInt8(0); // returns the number 5

// be careful here – we assigned an int8 to the first location, but we
// can ask for an int16
// (byte 1) 00000101 (byte 2 ) 00000000 together they make 0000010100000000
// (or 1280 in base 10)
dataView.getInt16(0); // 1280

As you can see in the above example, with a generic data view object you can access the data in any of the available formats. If this is not what you want, then use the type-specific data views.

let arrayBuffer = new ArrayBuffer(10); // allocates 10 bytes for this buffer

// access to 6 8-bit ints starting from the 1st byte (index 0)
let int8Array = new Int8Array(arrayBuffer, 0, 6);

// access to 2 16-bit ints starting from the 7th byte (index 6)
let int16Array = new Int16Array(arrayBuffer, 6, 2)

int8Array.length; // 6
int16Array.length; // 2

int8Array[0] = 127;
int8Array[0]; // 127
// assigning a number larger than can be represented with a signed byte
int8Array[1] = 128;

// binary overflow means the number flips around to -128
// 128 is 10000000 in binary and since we are using signed
// integers the first bit (1) indicates this is a negative
// number. The maximum positive number we can store
// is 01111111 (127)
int8Array[1]; // -128

int16Array[0] = 128;
int16Array[0]; // 128 – no binary overflow here!

Note: with the unsigned int arrays (Uint8Array, Uint16Array, Uint32Array) any value below 0 will loop back around to the maximum value available and any value above the maximum value will loop back around to 0. However, there is a special Uint8ClampedArray for unsigned 8-bit integers. In this case, any value below 0 will be capped at 0 and any value above 255 will be capped at 255.

How are they different from normal arrays?

  • Typed arrays aren't Arrays– they don't inherit from Array
Array.isArray(new Int8Array()); // false
  • A typed array's size can't be altered once it's been created. Any attempt at setting a value at a non-existent index will be ignored:
let int8Array = Int8Array.of(1, 2, 3);
int8Array[5] = 10;
int8Array; // Int8Array [ 1, 2, 3 ]
  • The following methods are not available for typed arrays as they could result in a typed array that has a different size:
    • concat
    • shift
    • pop
    • splice
    • push
    • unshift
  • The set and subarray methods are available on typed arrays, but not on normal arrays. set is used for setting multiple values in a typed array, and subarray is used for extracting a new typed array containing some of the elements of another typed array.
let ints = new Int8Array(4);

ints.set([2,3]); // sets the first element to 2 and the second to 3

// 2 is used as an offset index. The 3rd element is set to 5 and the
// 4th element is set to 8
ints.set([5, 8], 2);
ints; // Int8Array [ 2, 3, 5, 8 ]

let moreInts = Int8Array.of(1, 3, 5, 8, 13);
let clone = moreInts.subarray(); // Int8Array [ 1, 3, 5, 8, 13 ]
clone === moreInts; // false - subarray() creates a new typed array
moreInts.subarray(2); // Int8Array [ 5, 8, 13] – 2 is used as the offset index
moreInts.subarray(2, 3); // Int8Array [ 5 ] – the end index is exclusive

Where can I learn more?

Previous post: Test Driven Development

Next post: Proxies in ECMAScript