Discovering Array API goodies!
Tags: javascript, webdev, api
Published: 2019-04-17 10:26:59

**This post is taken from [my blog](https://areknawo.com), so be sure to check it out for more up-to-date content 😉**

Undoubtedly,  [**arrays**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)  are one of the most useful and extremely popular JS data structures. These  **indexed collections**  proved time and time again that they're still the best (if not only) choice for a various number of use cases. But, arrays themselves wouldn't be so valuable without their whole, extremely expressive  **API**. And that's the topic of today's post! 😀

We'll go over some lesser-known and other possibly hard to remember methods that are  **included natively**  within arrays API. Some dating back surprisingly quite much! With their help, you'll be able to write cleaner, more  **functional**  (in  [**FP-style**](https://en.wikipedia.org/wiki/Functional_programming)  also) and sometimes even more performant JS code! Some of them might be easier, some harder, but this article is definitely not aimed at total beginners! Of course, if you already know and remember all of them, consider at least taking a while to remind yourself some details or learn some  **new tricks**! ✨

# Transformation

For better reading experience, I divided all listed methods into  **4 separate groups**. Each one collects methods sharing at least one special property. The first group is called  _"Transformation"_. Here, all methods that transform the array into other forms find their place. All of them work in an  **immutable**  manner, returning new array in the result, without affecting the base one.

## [.filter()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)

I think I don't have to talk about how useful  **filtering**  arrays can be. And, with the  `.filter()`  you can do just that! All you have to do is pass a  **filtering function**, which, given current  **element's value**,  **its index**  and  **source array**, should output boolean value, indicating if the given element should or shouldn't be included in the resulting array. 📋

```javascript
const arr = [1,2,3,4];
const evenArr = arr.filter(num => num % 2 === 0); // [2,4]

```

## [.map()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)

`.map()`  is possibly one of the most beloved array methods in  **FP**-tailored JS programming. As you may already know, it processes (_"maps"_) your array and, with the given  **mapping function**, returns new one with freshly processed data. The mentioned function provides a  **standard parameters set**  of element, its index and source array parameters and should return value that's meant to be included in the result. So, with all that data, you should have everything you need to change your array the way you want! 😁

```javascript
const arr = [1,2,3,4];
const oneMoreArr = arr.map(num => num + 1); // [2,3,4,5]
```

## [.flat\[Map\]()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat)

**Nested arrays**  are quite common in modern days. They prove especially useful when representing 2D or 3D data formats. It's totally possible to go even deeper with such dimensions, but, as we all know, it later becomes only harder and harder to keep track of and access such data. Guys behind ECMAScript specification development clearly  [recognized this pattern](https://github.com/tc39/proposal-flatMap), and, beginning with  **latest ES specs**  and  **always-green browsers**, introduced new  `.flat()`  method to us. Its rules are simple - it simply  **flattens**  your nested array by specified depth (defaults to 1), effectively leaving you with an array more flatten than ever !

```javascript
const arr = [1,[2,[3,[4]]]];
const flatten = arr.flat(3); // [1,2,3,4]

```

There's yet another array-flattening-related method. I'm talking about  [`.flatMap()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap)  and, as you might expect, it's a perfect combination of  `.map()`  and  `.flat()`. Basically, you can use this method just like  `.map()`  - with the same set of parameters and etc., but the resulting array is later flattened  **1 level deep**. Simple. So, what are the possible use-cases of such method? For that, consider the example of string processing below.

```javascript
let arr = ["This is", "an", "example"];

const mappedArr = arr.map(x => x.split(" ")); 
// [["This","is"],"an","example"]

const flatMappedArr = arr.flatMap(x => x.split(" "));
// ["This","is","an","example"]
```

Maybe this is a bit sketchy, but I think you get the point. As soon as you understand how this method is working, you surely will find some use-cases of your own. As a side-note, this way is a bit  **more performant**  ⚡ than using  `.map()`  and  `.flat()`  separately.

# Interaction

_"Interaction"_  category groups all methods that  **work on the source arrays**  and, instead of providing an entirely new one, alter the them or return completely  **different types of values**. 🤯

## [.reverse()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse)

Certainly simple, but a bit lesser-known method,  `.reverse()`  does exactly what its name implies -  **reverses the ordering**  of elements inside your array. ➰ So the last shall be first. This will most likely come in handy when working with queues of different kinds. Remember that this method mutates the source array.

```javascript
const arr = [1,2,3,4];
arr.reverse(); // [4,3,2,1]

```

## [.reduce\[Right\]()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce)

If you want to quickly convert (_"reduce"_) your array to a single value, you can freely do it with the  `.reduce()`  method. Provided the right function (so-called  **reducer**), it will later execute it on every single element of an array and  **accumulate the result**  to a single variable.

```javascript
const arr = [1,2,3,4];
const sum = arr.reduce((sum, num) => sum + num); // 10

```

The argument function should return the accumulated value, which can be later referenced back with its first argument. At its peak, the function can provide you with  **4 parameters**  (in the given order):

-   **accumulated value**  (can be a string, array, object or whatever...);
-   the  **current value**  of array being reduced;
-   **index**  of current value;
-   **array**  being reduced;

If reduction order is important to you, you should know that you also have accessed to  [`.reduceRight()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/ReduceRight)  which does exactly the same thing as the previous method, but beginning from  **the right side**, going backward. 🔙

## [.find\[Index\]()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find)

Finding a particular element in the array can be a tough task unless it's the first or the last one of course. Here, added in ES6  `.find()`  method can be really helpful. It simply takes the  **checking function**  which handles the standard set of parameters, and returns the  **first matched value**from the given array,  `undefined`  otherwise.

```javascript
const arr = [1,2,3,4];
const matched = arr.find(num => num % 2 === 0); // 2

```

There's also an  [`.findIndex()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex)  method which, just like the first one, uses the matching function to find the value, but instead returns its index instead of raw value. It can be compared to  [`.indexOf()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf)  or  [`.lastIndexOf()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf), that also can be used to retrieve the index of the first and last value that matches the provided one, but it's not as  **expressive**  as  `.findIndex()`  with its matching function can be. 😑

```javascript
const arr = [1,2,3,4];
const matched = arr.findIndex(num => num % 2 === 0); // 1

```

One last note though - if you're using  `.indexOf()`  only to check if a value exists in the given array, consider using  [`.includes()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes)  (ES6 feature) - it returns a  **boolean**  and have a bit  **better performance**  than its alternatives.

## [.every()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every)

As much as some might expect  `.every()`  to simply run provided function on every element of the given array, the naming can be misleading here. Instead,  `.every()`  indeed runs a function on every element, but only to  **check if they follow provided guidelines**  and, in the end, return a rightful boolean value. Checking function provides the standard set of parameters. 👌

```javascript
const arr = [1,2,3,4];
const isIncremental = arr.every((num, idx, arr) => {
    const previousIdx = idx - 1;
    if(previousIdx >= 0){
        return num === arr[previousIdx] + 1
    } else {
        return true;
    }
}); // true

```

## [.copyWithin()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/copyWithin)

Copying data within the margins of a single array can feel a bit complicated and pointless for some. But, with its  **superior performance** 🌠 (especially in its  [TypedArrays](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray)  counterpart), this method provides a great way to  **shift array elements**  fast! Here, you can pass 1 up to 3 arguments:

-   the  **target index**  from which the copied data will be pasted. As  `.copyWithin()`  doesn't change the length of source array, elements will be replaced and old data removed.
-   the  **starting index**  marking the beginning of data to be copied (defaults to 0 - array's beginning)
-   the  **ending index**  marking the end (excluding the provided index) of data to be copied (defaults to  `.length`  - the end of the given array)

```javascript
const arr = [1,2,3,4];
arr.copyWithin(0,2); // Array.copyWithin() mutates the source array
arr; // [3,4,3,4]

```

## [.sort()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)

`.sort()`  is one of these methods that clearly does exactly what the name implies. In this case - it just  **sorts your array**. It could be with or without a  **comparison function**  provided. By default, all values are converted to strings and sorted increasingly  **by  [UTF-16](https://en.wikipedia.org/wiki/UTF-16)  code**  🌐 values, meaning numbers from smaller to bigger and strings alphabetically. You can also provide a function that receives two elements for comparison as separate parameters. This comparison function should  **return a number**, which will then be used to sort provided values in a given way:

-   if the function returns number  **less than 0**, the value provided as the  **first parameter**comes first;
-   if the function returns number  **equal to 0**, the values will remain  **unchanged**  (not really guaranteed by the specification);
-   if the function returns number  **higher than 0**, the value provided as the  **second parameter**comes first;

```javascript
const arr = [1,2,3,4];
arr.sort((num1, num2) => {
    return num2 - num1;
}); 
// Array.sort() mutates the source array

```

## [.some()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some)

`.some()`  is a method similar to  `.every()`. It checks if elements inside the source array  **satisfy certain rules**  (provided in the form of  **checking function**) and, in the end, returns a boolean value. The difference is that  `.some()`  requires  **only one element**  ☝ to satisfy the test, to return a positive value, unlike  `.every()`  which requires every element. It can help you, e.g. check if there's at least one value with given properties. Provided test function receives a standard set of parameters (element, its index and source array)

```javascript
const arr = [1,2,3,4];
arr.some((num) => {
    return num % 5 === 0;
}); // false

```

# Iteration

Surprise, surprise! 😲 There's, in fact, only one method in array API to perform iteration only! Just a shout-out to those who use  `.map()`,  `.reduce()`  and similar method, only to iterate over source arrays. There's only one method for this task and thus, it should be respected and well-known.

## [.forEach()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach)

`.forEach()`, does what its name stands for -  **iterates over each element**  of the source array. Provided a function that receives standard arguments set, it runs it on every element of the given array. 🔁

```javascript
const arr = [1,2,3,4];
arr.forEach((num) => {
    console.log(num); // 1/2/3/4
})
```

# Miscellaneous

Beyond all of the above categories, arrays API have some more methods in its stock. Below are some of them, that are surely  **lesser-known**  and used, but may come in handy in some special cases.

## [.entries()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/entries)

`.entries()`  is the first of 3  **iterator-object**-returning methods. The array iterator object or so-called  **iterable**  is a simple structure that can be, naturally, iterated through using  `for... of`  loop and has single  `.next()`  method which is called under-the-hood when iterating. When called directly, it returns an  **object**  containing  `value`  and  `done`  properties, which, respectively, indicate**current value**  and  **if iteration is complete**. ⏳ When called again, it will return the  **next value**from the array, and the process will continue until the end of the source array when the  `done`property will be set to  **true**.

Our iterator returned by  `.entries()`  method will have its values in the form of  **key-value pairs**(arrays), where the first element indicates the  **current index**  and second -  **respective value**. You can compare it (and other methods will talk about later) to their object counterparts. Functions like  `Object.entries()`  or  `Object.keys()`  (not on the prototype) are certainly more popular than their array siblings but do similar things.

```javascript
const arr = ["a","b","c","d"];
const iterable = arr.entries();
iterable.next(); // {value: [0, "a"], done: false}
iterable.next().value; // [1, "b"]
iterable.next().value; // [2, "c"]
iterable.next(); // {value: [3, "d"], done: true}

```

After iteration completes, it  **cannot be restarted**. The only way to do the same again is by creating a  **new iterable**  with the same method.

But what are the use-cases for such a method? Well, the  `.next()`  method certainly gives you a bit  **more control**  ✊ over how your array is iterated. Also, key-value-like pairs returned by  `.entries()`  can definitely prove to be useful, when wanting to have access to the element's value and index at the same time. But, in these cases, maybe  **standard objects**  or  **maps**  (which I talked about in the  [**previous post**](https://areknawo.com/rocking-js-data-structures/)) will serve you better.

## [.keys()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/keys)

With all complexity behind iterables already covered, there are two more methods similar to  `.entries()`  -  `.keys()`  and  `.values()`. The first one, as the name suggests, returns iterable with values equal to source  **array indices**  (aka keys). 🔢 Instead of key-value arrays, it returns  **numbers**  representing the indices of your array's elements.

```javascript
const arr = ["a","b","c","d"];
const iterable = arr.keys();
iterable.next(); // {value: 0, done: false}
// ...

```

## [.values()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/values)

The  `.values()`  method, again, returns iterable. This time its values are equal to  **source array elements' values**.

```javascript
const arr = ["a","b","c","d"];
const iterable = arr.values();
iterable.next(); // {value: "a", done: false}
// ...

```

## [.toString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toString)

The last method I'd like to talk about is  `.toString()`. It's present in JS objects, functions, strings, numbers, arrays and more! Possibly in every JS object (_everything is an object_)! But I think that still, with all its  _omnipresence_, the  `.toString()`  method is still not given as much interest as it deserves.

At its core, the  `.toString()`  method simply converts an array to string. The returned value has a form of square brackets, with array elements placed tightly together, divided by commas.

```javascript
const arr = [1,2,3,4];
const str = arr.toString(); // "[1,2,3,4]"

```

But its biggest advantage is that it doesn't have to be called directly!

```javascript
const arr = [1,2,3,4];
const str = `${arr}`; // "[1,2,3,4]"

```

In this way, every time your value needs to be converted to a string (e.g. string literals or concatenation), this  **method is called**. This and also the fact that you can freely change this method with  **your own implementation**  gives you the ability to not only return custom strings but also perform certain operations when doing so! ✨ Trust me - this allows you to do some pretty  **interesting tricks**!

# Array time!

So, these were my personal picks of some of the most interesting and worth-looking array API methods! Did you know all of them? I know that built-in API can be easily forgotten and thus lead to us searching for solutions to problems that don't really need to exist. I hope that this post helped you solve at least some of them. 😀

Now,  **what do you think of this article**? Write your opinions in the  **comment section**, and let me know if you liked it with  **a reaction below**! Also,  **follow me**  [**on Twitter** 🐦](https://twitter.com/areknawo),  [**my Facebook page**](https://www.facebook.com/areknawoblog) and consider checking out my [personal blog](https://areknawo.com)  to stay  **up-to-date**  ⏱ with the latest content from this blog. As always,  **thank you**  for reading this post and I'll see you in the next one! ✌