JavaScript ES6 Tutorial: Array Methods Explained

Understanding array methods is an important step towards being able to write clean, functional code, and it opens doors to more powerful techniques of functional and reactive programming.

Here at Scandiweb, we use arrays daily. A lot of arrays are processed throughout our workflow, whereas our job is to make it legit. We use arrays to show search lists, items added into a user cart, store media entities, and much more. Javascript Array inbuilt object provides some fascinating and helpful methods to manage data stored in arrays.

Let’s take a look at these methods to understand how to use them properly and avoid creating errors.

Note! This article explores the most often used array methods in more detail, providing real-world scenarios that demonstrate the scope of the array prototype to ensure that those solutions satisfy the best learning experience.


Array prototype cheat sheet

For code to be easier to reason about, you should avoid mutating arrays. Instead, it is preferred to create new arrays with the values you want. This will often be more concise, and make the data flow easier to follow © ScandiPWA Docs

Creating a new array by transforming each item

Array.prototype.map()—Calls the function for each value and returns the array of results

Return value: A new array with each element being the result of the callback function.

import React from "react";
import "./styles.css";

const names = ["whale", "squid", "turtle", "coral", "starfish"];

export default class App extends React.PureComponent {
  // Declare the mapper function once and for all
  renderMarineLifeItem = (name) => <p key={name}>{name}</p>;

  // Use the pre-declared mapper function here
  renderMarineLifeList = () => (
    <div>{ names.map(this.renderMarineLifeItem) }</div>
  );

  render() {
    return (
      <div className="App">
        <h1>MarineLife Sample</h1>
        { this.renderMarineLifeList() }
      </div>
    );
  }
}

Note! It is a really common practice to use map to render some list of items. map is great, isn’t it? But what if I told you that there is a potential monstrosity inside? Please avoid using arrow functions in renders:

<̶u̶l̶>̶{̶n̶a̶m̶e̶s̶.̶m̶a̶p̶(̶n̶a̶m̶e̶ ̶=̶>̶ ̶<̶l̶i̶ ̶k̶e̶y̶=̶{̶n̶a̶m̶e̶}̶>̶ ̶{̶n̶a̶m̶e̶}̶ ̶<̶/̶l̶i̶>̶)̶}̶<̶/̶u̶l̶>̶

The reason for this is the render cycles. Code samples from the web mostly have just a few render cycles, but what if there are one thousand? This results in 1000 redundant function declarations. Play around with the code here!

Keep in mind:

  1. The callback you pass to map must have an explicit return statement, or map will create an array full of undefined. Remember to include a return value!
  2. If you do forget, map won’t protest. Instead, it’ll quietly hand back an array full of nothing. Silent errors like that can be surprisingly hard to debug.

MDN Web Docs: Array.prototype.map() 

Reducing the array to 1 value

Array.prototype.reduce()—Combines all elements into 1 new value

Return value: The single value that results from the reduction.

There are a lot of benefits to understanding reduce. It is often used in state management (think Redux), and as a go-to option when the output array is expected to be a different length. Reduce comes with terminology such as reducer & accumulator. The accumulator is the end value, and the reducer is the action you perform to get to one value.

You have to remember that a reducer will return one value and one value only, hence the name reduce. Play around with the code here!

const superheroes = [
  { name: 'batman', type: 'fighting' },
  { name: 'superman', type: 'flying' },
  { name: 'aquaman', type: 'swimming' }
];

const getMapFromArray = (data) =>
  data.reduce((acc, item) => {
    // add object key to our object i.e. batman: { type: 'fighting' }
    acc[item.name] = { type: item.type };
    return acc;
  }, {});

getMapFromArray(superheroes);

Changing an Object Structure using reduce

Keep in mind:

  1. With reduce, you also have to include a return statement and the initial value
  2. Don’t expect an array, since reduce returns a single value

MDN Web Docs: Array.prototype.reduce()

Copying part of the array

Array.prototype.filter()—Returns a copy of the array with only those items that meet the specified condition

Return value: A new array with the elements that pass the test. If no elements pass the test, an empty array will be returned.

You need to ensure that no null or undefined values will attempt to break your code. How cool is it that you can achieve this with just one line of code?

const attributes = {
  size: {
    attribute_label: 'Size',
    code: 1
  },
  color: {
    attribute_label: 'Color',
    code: 2
  },
  material: {
    attribute_label: undefined,
    code: 3
  },
  texture: {
    attribute_label: null,
    code: 4
  }
};

const labels = Object.values(attributes)
  .filter((attribute) => attribute && attribute.attribute_label) // Filter out null and undefined values
  .map(({ attribute_label }) => attribute_label); // create a map from attribute_label values of a new filtered array

// ["Size","Color"]

Filtering out attribute values to avoid null and undefined

Keep in mind:

  1. With filter, you also have to include a return statement (unless you’re using arrow functions), and you must make sure it returns a boolean value.
  2. If you forget your return statement, the callback will return undefined, which filter will unhelpfully coerce to false. Instead of throwing an error, it will silently return an empty array.
  3. If you go the other route and return something that isn’t explicitly true or false, then filter will try to figure out what you meant by applying JavaScript’s type coercion rules. More often than not, this is a bug. And, just like forgetting your return statement, it’ll be a silent one.

MDN Web Docs: Array.prototype.filter()

Reordering the array

Array.prototype.sort()—Sorts the array according to the specified ordering function

Return value: The sorted array. Note that the array is sorted in place, and no copy is made.

// Assuming we have received an unsorted breadcrumbs array
const breadcrumbs = [
  {
    category_name: "Home",
    category_level: 1,
    category_url: "/",
    category_is_active: true
  },
  {
    category_name: "Personal Care",
    category_level: 3,
    category_url: "/health-beauty/personal-care.html",
    category_is_active: true
  },
  {
    category_name: "Health & Beauty",
    category_level: 2,
    category_url: "/health-beauty.html",
    category_is_active: true
  }
];

// Simply sort it ascending based on the category_level value
const sortedBreadcrumbs = [...breadcrumbs].sort((a, b) => a.category_level - b.category_level);

Sorting the breadcrumbs array based on the category_level value

Please note the following syntax:

const sortedBreadcrumbs = [...breadcrumbs]

Since Array.prototype.sort() mutates an array without making a copy, I have made it manually to show the Spread syntax in action. Remember that it is not always required to clone an array. Play around with the code here!

Keep in mind:

  1. Not only does sort return the re-ordered array but also changes the original one. For this reason, it is not ideal from the functional programming perspective. Most of the time, mutating the original array might be acceptable. If you do not wish to mutate the array, create a copy of it and re-order the copy instead.
  2. By default, the sort() method sorts the array elements in ascending order, with the smallest value first and the largest value last. Note! Unfortunately, invoking the method on numbers performs the same alphabetical sorting. To correctly sort numbers in ascending order, you should use the comparison function (shown hereinbefore).
  3. There’s a big caveat to the string sorting method. It doesn’t take into account Unicode and non-English alphabets. Depending on your application, you might want to consider using the String::localeCompare() instead, which has built-in support for things like language-specific sort ordering, ignoring cases, or diacritics:
const strings = ['č','é','A','b','Đ'];
const localeSort = Array.from(strings).sort((a, b) => {
  return a.localeCompare(b, 'en', { sensitivity: 'base' });
});

// ['A', 'b', 'č', 'Đ', 'é']

Sorting locale strings array in ascending order

MDN Web Docs: Array.prototype.sort()

Best practices

Adding an item to the array

const newItem = 42;
const array = [1, 2, 3];
const newArray = [newItem, ...array];
// [42, 1, 2, 3]

Removing an item from the array

const itemToRemove = 42;
const array = [42, 1, 2, 3];
const newArray = array.filter(item => item !== itemToRemove);
// [1, 2, 3]

We hope this article taught you something new. Looking to learn more about ScandiPWA? Feel free to get in touch: write us a message at [email protected]web.com, book a free consultation, or schedule a call!

If you enjoyed this post, you may also like