# Uint8Array vs DataView: Choosing the Right Buffer View in JavaScript

In the previous article, we got familiar with [JavaScript buffers](https://pavel-romanov.com/javascript-buffers-explained-why-they-matter-and-how-to-use-them). The lowest possible implementation of a buffer in JavaScript is the `ArrayBuffer` class. This class is read-only, meaning we don't have any API to write data inside the buffer.

To change buffer content, we have two options: data views and typed arrays. In this article, we'll talk about data views, typed arrays, and their differences.

## Data views

Data view is the abstraction that allows you to change the content of a buffer. It acts like a key to a locked door. You can't go inside without having a key, but once you have it, feel free to come in.

The same is true for the relation between buffer and data view. Data view is like a key that allows you to write data inside a buffer. Data view is represented by the `DataView` class in JavaScript.

It holds the key to the underlying `ArrayBuffer` instance where data is stored.

You can see example in the code snippet below.

```typescript
const buffer = new ArrayBuffer(8);
const view = new DataView(buffer);

console.log(view.buffer.byteLength); // Prints 8

view.buffer.resize(5);

console.log(buffer.byteLength); // Prints 5
```

Notice that the `buffer` size changed after the buffer that view references was resized. This means that the view references the same buffer that we passed into the `DataView` class constructor.

When we want to write into a buffer using data view, we call one of the methods that set different types of values.

```typescript
const buffer = new ArrayBuffer(16);
const view = new DataView(buffer);

view.setUint8(0, 0x0F);

console.log(view.getUint8(0)); // Prints 15
```

When we call the `setUnit8(0, 0xF)` method, it writes the value of `0x0F` inside the buffer using 1 byte for it.

## Typed arrays

The second option to change buffer data is typed arrays. Don't be confused by the **array** part. Typed arrays aren't arrays but **array-like** structures.

What it means is when you use `Array.isArray` function and pass a typed array inside it returns `false`. At the same time, typed arrays provide many array-like methods: `at`, `fill`, `map`, `reduce`, etc. That's why typed arrays are called array-like structures.

In JavaScript, we have many different typed arrays such as:

* `Uint8Array`
    
* `Int8Array`
    
* `Uint16Array`
    
* `Int16Array`
    
* `Float32Array`
    
* `Float64Array`
    

And others. Every typed array provides the ability to modify the underlying buffer. But what is the difference between all those typed arrays and when to use which?

To understand this topic better, I highly recommend reading the article about [different types of text encoding schemes in JavaScript](https://pavel-romanov.com/from-ascii-to-unicode-a-javascript-developers-guide-to-text-encoding). Knowing text encoding schemes makes it much easier to understand the topic of typed arrays.

There are 3 main characteristics of the typed arrays you should know about:

* Signed and unsigned typed arrays
    
* Number of bytes required to store a single value inside a typed array
    
* Type of value that a typed array can store
    

Let's look at each of them in more detail.

### Signed and unsigned typed arrays

The meaning of the data that the buffer contains heavily depends on the context in which it is interpreted.

```typescript
const signedArray = new Int8Array([0xFF, 0x75, 0x6E]);
const unsignedArray = new Uint8Array([0xFF, 0x75, 0x6E]);

// Prints Int8Array {0: -1, 1: 117, 2: 110}
console.log(signedArray);

// Prints Uint8Array {0: 255, 1: 117, 2: 110}
console.log(unsignedArray);
```

Quick note, if you're not comfortable with those `0xFF` and other hexadecimal values, check out the article in which we dive into the [hexadecimal numeric system in JavaScript](https://pavel-romanov.com/numeric-systems-in-javascript-from-fundamentals-to-application).

You see that both structures are almost identical. The only difference is that the first element with a value of `OxFF` in signed arrays is treated as `-1`, and in unsigned arrays, it is `255`. That's the whole point of signed vs. unsigned, the range of *possible* values is different.

Signed arrays can contain both negative and positive values. Unsigned array can only contain positive values. The specific range of values is dictated by how many bytes are used to store a single item.

### Number of bytes required to store a value

Typed arrays store values differently. To be more precise, each typed array allocates a different number of bytes to store a single item.

![The difference between how typed arrays store values](https://cdn.hashnode.com/res/hashnode/image/upload/v1723039758036/c896e446-4126-406c-8180-8b407f1a9122.jpeg align="center")

For the same piece of data, different typed arrays allocate different number of bytes.

%[https://x.com/pavl_ro/status/1820489696801444057] 

To better understand when to use which typed array, you have to understand the data you're working with.

If the data is not expected to exceed the range from `0` to `255`, then it is better to use `Uint8Array`. It operates in this exact range, and it is one of the most memory-efficient type arrays.

If you expect to work with data where some elements can have a value higher than `255` it is better to use `Uint16Array` or `Uint32Array`. If you try to write a value higher than `255` into an 8-bit unsigned array, the value will be cut at `255`.

```typescript
const u8Array = new Uint8Array([0xFFF]);
const u16Array = new Uint16Array([0xFFF]);

console.log(u8Array) // Prints Uint8Array {0: 255}
console.log(u16Array) // Prints Uint16Array {0: 4095}
```

### Different value types

Different typed arrays are meant to store different datatypes. So far, we've talked only about integer typed arrays. The integer, in this case, is a number without any floating point numbers like `3` or `120`. But what if you want to store values with floating point numbers like `3.14`?

```typescript
const u8array = new Uint8Array([3.14]);

// Prints Uint8Array {0: 3}
console.log(u8Array);
```

The part after the floating point gets cut, and you only see `3`. To store floating point numbers, you have to use specific typed arrays `Float32Array` or `Float64Array`.

```typescript
const float32array = new Float32Array([3.14]);

// Prints Float32Array {0: 3.140000104904175}
console.log(float32array);
```

Now you can see the numbers after the floating point.

## What is the difference between a data view and a typed array

It looks like we have 2 things that are doing basically the same. Well, it is partially true because both `DataView` and `TypedArray` are buffer views.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723040152869/b9d6ab33-231d-4d0f-977e-e08800d0b1f1.jpeg align="center")

As you can see, using both abstractions gives you the same power to edit buffers' content. At the same time, there are differences in *how* they're editing buffer content.

### Scope of manipulated data

When dealing with typed arrays, we always work with a specific type of data. For example, using `Uint8Array` means that we only work with data range between `0` and `255`.

Typed arrays are quite convenient when we work only with a single type of data per buffer. However, this is not the case if we want to write different types of data inside a buffer. It is still possible to use typed arrays for it, but the code becomes more tedious.

```typescript
const buffer = new ArrayBuffer(10);
const u8Array = new Uint8Array(buffer, 0, 3);
const u16Array = new Uint16Array(buffer, 3, 3);

u8Array.fill(0xFF);
u16Array.fill(0xFFF);

// Prints Uint8Array {0: 255, 1: 255, 2: 255}
console.log(u8Array);

// Prints Uint16Array {0: 4095, 1: 4095, 2: 4095}
console.log(u16Array);
```

Using `DataView` is more convenient in such cases because you're not constrained by any particular type of data.

```typescript
const buffer = new ArrayBuffer(10);
const view = new DataView(buffer);

view.setUint8(0, 0xFF);
view.setUint16(1, 0xFFFF);
```

You don't need to work with many abstractions and variables. `ArrayBuffer` and `DataView` are enough for this task.

### The difference in how a data view and a typed array treat Endianness

If you're not familiar with Endianness, check out this section of the article on [bits and bytes in JavaScript](https://pavel-romanov.com/from-binary-to-code-why-javascript-devs-need-to-know-bits-and-bytes#heading-bytes-and-memory).

By default, typed arrays only work with the native Endianness of your platform. For example, if you have little-endian hardware, then typed arrays use little-endian byte order when working with typed arrays.

Most modern machines use little-endian bytes order. However, it doesn't mean there is no place for big-endian.

In [this](https://stackoverflow.com/questions/7869752/javascript-typed-arrays-and-endianness) StackOverflow question user faces the problem where a big-endian WebGL file is interpreted in little-endian using typed arrays. It happens because the native system byte order is little-endian.

To solve the issues, we can use `DataView`. Data views allow you to change the way how the view treats the buffer byte order.

```typescript
const buffer = new ArrayBuffer(10);
const view = new DataView(buffer);

view.setUint16(0, 0xFFF, true);
```

When we pass `true` as the third argument to `DataView` instance methods, it means that we intend to store the data in little-endian byte order. By default, `DataView` uses big-endian byte order to store the data.

Notice that methods which set 8-bit values like `setUint8` and `setInt8` don't have this flag. The reason is simple, there is only 1 byte, and the byte order is irrelevant in this case.

## Conclusion

Views allow you to change the content of a buffer. There are two types of views: typed arrays and data views.

Data view is represented by the `DataView` class in JavaScript. There is only one class when it comes to data view, and through this class, we can set many different values for the buffer.

On the other hand, typed arrays are represented by multiple different class that differs by:

* Signed and unsigned type
    
* Number of bytes required to store a single buffer item
    
* Type of data stored like integers, floats, big integers
    

The difference between data view and typed array lies in how flexible you want to be when working with buffers. If you want to primarily work with a single type of data and ok without having much flexibility, then typed arrays are your choice.

On the other hand, if you need a more flexible solution or you want to work with different types of data inside a single buffer, then data views are the way to go.
