JavaScript Typed Arrays: Binary Data, Buffers, and Views

Typed arrays let you work with raw binary data in JavaScript using compact, fixed-size numeric arrays. They are essential for files, graphics, audio, network protocols, and any code that needs predictable memory layout.

Quick answer: A typed array is a numeric view over an ArrayBuffer. It stores one specific number type, such as bytes or 32-bit integers, and is much better than a normal array when you need binary data or performance-sensitive memory access.

Difficulty: Intermediate

You'll understand this better if you know: basic arrays, JavaScript numbers, and how objects can reference shared data.

1. What Is Typed Arrays?

Typed arrays are array-like objects designed for binary data. Unlike normal JavaScript arrays, they store values in a fixed numeric format such as 8-bit unsigned integers or 32-bit floating-point numbers.

In practice, you usually create a typed array when you need to read or write binary bytes directly instead of managing ordinary JavaScript values.

2. Why Typed Arrays Matter

JavaScript arrays are flexible, but that flexibility is not always what you want. If you are handling image pixels, audio samples, compressed data, or network packets, you need a structure that matches the binary format exactly.

Typed arrays matter because they provide predictable storage, efficient numeric access, and a clean way to share the same memory across different views. That makes them useful in browser APIs, Node.js, and WebAssembly integrations.

They are not meant to replace regular arrays in everyday application code. Use them when the data is truly binary or when you need tight control over bytes and numeric representation.

3. Basic Syntax or Core Idea

Creating a buffer and a typed array

The simplest typed array uses an ArrayBuffer plus a typed view such as Uint8Array. The buffer owns the bytes, and the typed array decides how to interpret them.

const buffer = new ArrayBuffer(8);const bytes = new Uint8Array(buffer);bytes[0] = 255;bytes[1] = 42;console.log(bytes);

This code creates 8 raw bytes and exposes them as an unsigned 8-bit array. Each element must stay between 0 and 255.

Common typed array constructors

JavaScript provides several typed array classes for different numeric ranges and use cases.

Each constructor determines how values are stored and read from the same underlying bytes.

4. Step-by-Step Examples

Example 1: Filling a byte buffer

This example shows the most common starting point: create bytes, write values, and read them back.

const bytes = new Uint8Array(4);bytes[0] = 10;bytes[1] = 20;bytes[2] = 30;bytes[3] = 40;console.log(bytes[2]);

Here, the typed array behaves like a numeric list, but each entry is stored as a single byte.

Example 2: Shared memory with two views

The same bytes can be viewed in different ways. This is one of the biggest strengths of typed arrays.

const buffer = new ArrayBuffer(8);const bytes = new Uint8Array(buffer);const words = new Uint16Array(buffer);bytes[0] = 1;bytes[1] = 0;console.log(words[0]);

Both views point at the same memory, so changing one affects the other. This is useful for parsing binary formats efficiently.

Example 3: Converting from a regular array

You can build a typed array from a normal array when you already have numeric values.

const source = [3, 7, 11];const values = new Int16Array(source);console.log(values);

This copies the numbers into a fixed numeric format. If a number cannot fit the target type, it is converted according to that type’s rules.

Example 4: Using subarray for a slice-like view

Typed arrays can create lightweight views over part of the same buffer.

const data = new Uint8Array([10, 20, 30, 40, 50]);const middle = data.subarray(1, 4);middle[0] = 99;console.log(data);

subarray does not copy the data. It returns a new view into the same memory, so edits affect the original buffer.

5. Practical Use Cases

When you see raw bytes or a spec that defines field sizes in bits and bytes, typed arrays are usually the right tool.

6. Common Mistakes

Mistake 1: Expecting typed arrays to behave like normal arrays

Typed arrays look like arrays, but they follow stricter rules. You cannot store strings, objects, or out-of-range values the way you can in a regular array.

Problem: This code assumes a typed array can hold any kind of data, but typed arrays only store numbers in their defined numeric range.

const items = new Uint8Array(3);items[0] = "hello";items[1] = { value: 1 };

Fix: Use a regular array if you need mixed data, or convert only numeric values into the typed array.

const items = ["hello", { value: 1 }];const bytes = new Uint8Array([1, 2, 3]);

The corrected version separates general-purpose arrays from numeric binary storage.

Mistake 2: Confusing shared views with copies

Methods like subarray create a view, not a copy. Many bugs happen when a developer expects one buffer to stay unchanged.

Problem: Changing the subarray also changes the original data because both objects reference the same underlying bytes.

const source = new Uint8Array([1, 2, 3, 4]);const view = source.subarray(1, 3);view[0] = 99;console.log(source);

Fix: Use slice when you need a copied typed array.

const source = new Uint8Array([1, 2, 3, 4]);const copy = source.slice(1, 3);copy[0] = 99;console.log(source);

The fixed version protects the original data because slice copies the selected bytes.

Mistake 3: Assuming all numeric types store the same range

Each typed array has its own numeric limits. Writing a value outside the range can wrap, clamp through conversion rules, or lose precision.

Problem: A Uint8Array cannot preserve values larger than 255, so direct assignment produces unexpected wrapping behavior.

const bytes = new Uint8Array(1);bytes[0] = 300;console.log(bytes[0]);

Fix: Choose a type that matches the data range, or validate values before storing them.

const values = new Uint16Array(1);values[0] = 300;console.log(values[0]);

The corrected version works because the selected type can represent the full value without unwanted conversion.

7. Best Practices

Practice 1: Pick the narrowest type that fits your data

Smaller types use less memory and often match binary formats more closely. If your data is a stream of bytes, Uint8Array is usually the best starting point.

const pixelBytes = new Uint8Array(1024);

Using the narrowest useful type keeps your code efficient and easier to match against external data formats.

Practice 2: Use DataView for mixed binary layouts

If a binary protocol mixes integers of different sizes or byte orders, DataView is often a better choice than one typed array type.

const buffer = new ArrayBuffer(4);const view = new DataView(buffer);view.setUint16(0, 500, true);view.setUint16(2, 900, true);

This approach is more flexible when the byte structure is not uniform.

Practice 3: Prefer slice when you need isolation

Use subarray for speed and shared-memory workflows. Use slice when a new copy is safer and easier to reason about.

const original = new Uint8Array([5, 6, 7]);const safeCopy = original.slice();

This reduces accidental mutation bugs when different parts of your program should not share memory.

8. Limitations and Edge Cases

A common source of confusion is that typed arrays feel list-like, but they are really fixed numeric views over raw memory.

9. Practical Mini Project

In this small example, we will build a simple grayscale pixel buffer and invert its values. This is the kind of task typed arrays are designed for.

const pixels = new Uint8Array([0, 64, 128, 192, 255]);for (let i = 0; i < pixels.length; i++) {  pixels[i] = 255 - pixels[i];}console.log(pixels);

This project shows how typed arrays are often used in practice: iterate through bytes, transform them in place, and keep memory usage predictable.

10. Key Points

11. Practice Exercise

Expected output: a typed array containing [4, 8, 12, 16, 20].

Hint: Use a for loop and assign back into the same array.

const numbers = new Uint8Array([2, 4, 6, 8, 10]);for (let index = 0; index < numbers.length; index++) {  numbers[index] = numbers[index] * 2;}console.log(numbers);

12. Final Summary

Typed arrays give JavaScript a practical way to work with binary data using fixed numeric storage. They are not a replacement for regular arrays, but they are the right choice whenever your data is really bytes, samples, pixels, or protocol fields.

Once you understand the relationship between ArrayBuffer, typed array views, subarray, slice, and DataView, you can read and write binary formats with much more confidence. If you want to go further, the next step is learning ArrayBuffer and DataView in more depth, especially for endianness and multi-byte parsing.