JavaScript Jungle: Curious case of sparse array in JS
Tags: javascript, webdev, beginners, development
Published: 2021-09-19 11:16:12

I have never heard about `sparse` array before one of my colleagues shared this interesting issue. 

```js
 const range = new Array(10).map((_, i) => i);
```

This code looks good to me. What can go wrong!! It should create the array of `length` `10` which will have values ranging from `0 - 10`. 

```js
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
```
Let's see....

 ![giphy](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/079h7rp18mu6j7jq9pzv.gif)

##Output 

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yluo2qc9pyn9cqp3bdtz.png)

Whhaaaatttt on the earth is that output.....!!!!  

The length of the array is `10` but when we try to access the value at index `0` the output is `undefined`. Same for other indices.  

Ok. That is super weird. Next thing that usually comes to mind is this:

> `map` isn't working. Let's use `forEach`. 


```js
 const range = [];
 new Array(10).forEach((_, i) => range.push[i]);
```

![giphy (1)](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/88ny6hx3h5sx698o430f.gif)
  
##Output

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gy08ts88lvqrsxphdxci.png)

**Nooooooooooo!!**

![giphy (2)](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/34nwhylp60q1hwxw5siq.gif)
  
Earlier, at-least we had length `10` which was what we expected. But now we lost that too. As you can see above in the output that `length` of `range` is `0` and since `length` is `0` that's why no element at any indices, that's why we get `undefined` at `range[0]`

Code looks correct, then why is it that output is unexpected. 

Actually all these unexpected behaviour is caused by `sparse` array. 

OK. So what on earth is **sparse array** ?

##Enter the maze


**Sparse Array**

> Any `array` will be `sparse` array if one of the `value`s at any given `index` is `empty`

Empty value does not mean `undefined` or `null`. Empty mean that there is no value at all. 

So in above example if I print `range` in `chrome` browser console. This will be the output: 

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lbwgkh7ozg4a738aaojx.png)

Basically `new Array(length)` will create an array of specified length but all the values will be `empty`. It's like array has `holes` in it. 

You can create the `sparse` array by following: 

```js
const range = [,,,];
const numbers = [1,2,,4];
const planets = ['earth', 'venus', 'mars'];
delete planets[1]; 
// when we delete element at certain index it creates a hole
```
##Output

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y9y2agvenn9zmbns2fme.png)

##Explanation of the real issue

Now we know about `sparse` array. So let's begin with our initial problem. 

## Scenario 1 : map

```js
 const range = new Array(10).map((_, i) => i);
```

So here `new Array(10)` will create a `sparse` array of `length` `10`. 

```js
(10) [empty × 10]
```

Now what will happen when we call `map` on `sparse` array ? 
As per [MDN Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map#parameters_in_detail)

> Due to the algorithm defined in the specification, if the array which map was called upon is sparse, resulting array will also be sparse keeping same indices blank.

As our whole array is `sparse` that is why resulting array is also `sparse` and all the values are `blank` or `empty`.

If we have following code, result will be different

```js 
[1,2,,4].map((num, i) => i * num)
```
##Output 

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k4h0ibwtoqzmi7sxrttf.png)

As you can see that `callback` of `map` does not do anything on the `index` which is `empty`. 

## Scenario 2: forEach

```js
 const range = [];
 new Array(10).forEach((_, i) => range.push[i]);
```
 As per [MDN Example](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#examples) 

> No operation for uninitialised values (sparse arrays)

Which simply means that the `callback` will not be invoked for `empty` values. 

As our whole new array is `sparse`, callback will be skipped for all the elements and no value is pushed to `range` array. 

## Other ways to create range

**With Array.from**

```js
 Array.from({length: 5}, (_, i) => i);
```

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d8zkgcu78brq8a1meju3.png)
 

**With new Array(length) and fill**

```js
  const a = new Array(3).fill(0).map((_, i) => i)
```

##Output 

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j2io3roxn666vllcf0e1.png)

Thank you for reading. 

Follow me on [twitter](https://twitter.com/VikasYadav_Dev)
 
## What to read next


{% link https://dev.to/xenoxdev/javascript-jungle-convert-any-object-to-iterable-40l6 %}

##References 

[MDN Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)
[2ality](https://2ality.com/2012/06/dense-arrays.html)
[Freecodecamp article](https://www.freecodecamp.org/news/sparse-and-dense-arrays-in-javascript/#:~:text=A%20sparse%20array%20is%20one,the%20sequence%20of%20their%20indices.&text=Normally%2C%20the%20length%20property%20of,sparse%20arrays%20they%20don't.)