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.
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:
- The callback you pass to
map
must have an explicitreturn
statement, ormap
will create an array full ofundefined
. Remember to include areturn
value! - 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:
- With
reduce
, you also have to include a return statement and the initial value - 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:
- 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. - If you forget your return statement, the callback will return
undefined
, whichfilter
will unhelpfully coerce tofalse
. Instead of throwing an error, it will silently return an empty array. - If you go the other route and return something that isn’t explicitly
true
orfalse
, thenfilter
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:
- 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. - 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).
- 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], book a free consultation, or schedule a call!
Share on: