Improve Code Readability While Working with Javascript Arrays
By: Keith Dawson
Tags: Coding, Code Readability, Programming, JavaScript, Arrays

While working with many other developers over the years to create Javascript applications, one of the things that I have found most striking is the lack of diversity in approaches that developers take while working with arrays. Over the past several years there have been many useful functions that have been added to the Javascript Array global object.

In addition to eliminating the need to constantly reinvent the wheel in so many similar or identical coding situations, these functions also provide developers with the ability to leave behind code for other developers that is much cleaner and more readable.

One of the things that I have always stressed throughout my career when mentoring other developers is the importance of writing code that is as easy to read as any plain English sentence. Not only should your logic operate according to the requirements of the software that you are writing, but for you or anyone else who reads your code in the future it should be a quick and easy task to figure out what exactly that code is doing.

As developers, we look at thousands of lines of code every day. It is far from an easy task, and in many cases a rather painful task, to go through large and complex applications to figure out exactly how they work, even when their code is well-written. When the code is cryptic and difficult to decipher, it certainly does not make such tasks any easier or less painful. In this article, I will be discussing a number of Javascript Array functions that you can use to not only inject some variety into your code, but more importantly, improve the overall readability of your code when working with arrays.

for loop

When it comes to working with arrays, the granddaddy of all modern techniques is the for loop. In Javascript, a for loop has three major features: the initial expression, which allows you to set the starting criteria for loop iteration; the condition expression, which allows you to set the ending criteria for loop iteration; and the increment expression, which allows you to set the criteria for incremental advancement from the beginning to the end of the loop iteration.

Another useful feature of for loops is the ability to use a break statement, which allows you to end iteration of the loop early if specific criteria defined in the loop logic have been met. In reality, for loops are not specifically tied to arrays in Javascript, but they were one of the earliest ways in which you could work with arrays efficiently and logically.

For the sake of completeness, the following code sample demonstrates the use of a for loop in Javascript to calculate the total cost of a list of expenses:

Traditional Javascript for loop

As a developer coming upon this code, I would need to pause for a moment to review the logic and figure out what exactly this code is trying to do. First, I would need to look at the three expressions defined at the top of the for loop to determine what they are doing. If any of these expressions were defined differently than they are in this code sample, which would be considered the typical and most common way to define a for loop, there could be some confusion as to what exactly this code sample is trying to achieve. After reviewing the expressions, I would then need to examine the for loop logic to figure out what that is trying to do.

This code sample does not do so, but if the code sample were to also have included a break statement, it might even take more time to figure out what exactly the entire for loop is trying to achieve because that would introduce additional complexity into the for loop logic.

In this particular code sample, the totals for a list of expenses are being summed to produce a grand total for all of the expenses. If you were to read this code sample as a sentence, it might look something like this: For every expense in a list of expenses, from the first expense to the last expense, the expense total is added to a grand total.

My main purpose for providing this example of typical for loop usage is to demonstrate its lower level of readability in comparison to other code samples that we will see later in this article. Also, all further code samples in this article will work with the same dataset as defined in this first code sample in order to ease the comparison process.

Array.forEach() function

The first function that I want to look at is the forEach() function, which is basically exactly what you would get if you were to create the for loop from the previous code sample in function form. If you wanted to improve the readability of a for loop that you have written by translating it directly to a function, the forEach() function is what you would use during that transfer process.

This function is simple in that it takes only one parameter, a parameter function that is applied to every item in the original array. The only parameter to this parameter function is each array item. Most of the functions that I will cover in this article have the same function signature as this function. Let’s see a code sample using the forEach() function, along with the equivalent for loop code for comparison:

Javascript Array.forEach() function

As you can see in this code sample, the logic within the parameter function passed to the forEach() function is almost identical to the logic contained inside the equivalent for loop code. By transferring that logic into a function with a much clearer name, it is easier to read and understand that the total of each item in the entire expenses list is being added to a variable external to the function in order to produce a grand total of all expenses.

Due to the appropriate name given to this function, you can read the forEach() function code in this code sample like this: For each expense in the expenses list add the expense total to a grand total. Despite the logic being almost identical in the two different versions of the code, this sentence for the forEach() function code conveys what is happening much more clearly and succinctly than the sentence used to describe the equivalent for loop code.

The one drawback with using the forEach() function, as well as all of the functions presented in this article, is that you cannot explicitly specify a break statement to end execution of the function early. This is not a problem, however, because some of the functions actually have built-in break statements and they will end their loop execution early in most cases before iterating over the entire array. Functions that behave this way do so depending on their intended purpose. Where applicable I will state when such behavior is possible while discussing functions further along in this article.

Array.map() function

Another function that we can use to improve code readability over and above a for loop is the map() function. Along with the forEach() function, the map() function is probably one of the most widely used array functions that I have encountered in Javascript code written by other developers. The map() function is essentially the same as the forEach() function, except for the function return value. The forEach() function does not return any results and simply executes a parameter function on each item in an array.

The map() function executes a parameter function on each item in an array, but it returns a new list containing the return value from each iteration of that parameter function. This parameter function is the only parameter accepted by the map() function.

Choosing between using the map() function and the forEach() function is generally dictated by whether or not you need to produce a completely new array of items containing the same number of items as the original array. As the function name suggests, what you are doing when using the map() function is mapping each of the items in the original array to a completely new item in the resulting array. Let’s see a code sample using the map() function, along with the equivalent for loop code for comparison:

Javascript Array.map() function

In this code sample we are using the same input as the forEach() function code sample, but instead of working with an external array we are producing a completely new array filled with an updated list of expenses. In addition to all of the data contained in the original array, each item in this new array also contains a pre-tax expense total.

The logic for the map() function code and the equivalent for loop code is more strikingly different here than it was in the forEach() function code sample. Rather than having to work with an external array the function simply produces its own new array upon completion of function execution. The map() function code in this code sample could be read like this: Update a list of expenses so each expense also contains a pre-tax expense total.

This is just one example of how the map() function could be useful in comparison to the forEach() function. Any time when you would like to produce a new array of items based on the items in an existing array, use the map() function. The new array of items could be an updated list of items from the original array that we saw in this code sample or it could be an entirely new list with no direct structural connection to the original array.

The key to remember when using the map() function is that the new array will have the same length as the original array. The forEach() function is more appropriate for when you would like to work with some existing external value or data structure and do not require an entirely new array to be produced by the function.

Array.filter() function

A function that is similar to the forEach() and map() functions but produces a different result then both is the filter() function. Like the forEach() and map() functions, the filter() function iterates through every item in the original array. Similar to the map() function, it produces a new array of items, but the difference is that the items in that new array are the same items in the original array for which the parameter function to the filter() function returns a truthy value. Let’s see a code sample using the filter() function, along with the equivalent for loop code for comparison:

Javascript Array.filter() function

In this code sample we are using the same input as before, but this time we are filtering the full list of expenses into a new list containing only food expenses. Just like in the map() function code sample, the difference between the filter() function code and the equivalent for loop code is substantial. Just like with the map() function, it is not necessary to work with an external array because the filter() function produces its own new array upon function execution completion. The filter() function code in this code sample could be read like this: Filter a list of expenses into a list of food expenses.

Unlike the map() function, which is guaranteed to return an array containing the same number of items as the original array, the filter() function can return an array containing as few as zero items or as many items as there are in the original array. This is entirely determined by the logic contained in the parameter function that is passed to the filter() function.

Array.reduce() function

With the map() and filter() functions covered, another useful function that we can look to for assistance in increasing the readability of our code is the reduce() function. This function is a bit more complicated than the other functions that we have covered so far, but in many ways, it is a cross between the map() and filter() functions. For parameters the reduce() function takes a parameter function that will be applied to every item in the array, as well as an initial value that will be passed to that parameter function on its first iteration.

The parameter function accepts two parameters. The first parameter is an accumulator, which begins with the first loop iteration as the initial value passed to the reduce() function. This accumulator parameter will continue to be carried forward to the next loop iteration as the value returned from the previous iteration of the parameter function, and it will ultimately be the value that is returned by the reduce() function once execution has completed. In order to get a better idea of how this works, let’s see a code sample using the reduce() function, along with the equivalent for loop code for comparison:

Javascript Array.reduce() function

The reduce() function is special because, rather than depending on the use of an external variable, like in the equivalent for loop code here or even in the case of the forEach() function, the function maintains its own internal variable across loop iterations. In this code sample that variable is total , the first parameter to the parameter function, and it would begin with the value of 0 , the second parameter passed to the reduce() function. This variable would be the equivalent of the grand total variable from the forEach() function code sample. The reduce() function code in this code sample could be read like this: Reduce a list of expenses down to a food expenses grand total.

The reason why I stated earlier that the reduce() function is almost like a cross between the map() and filter() functions is because it is able to serve the same purpose as both of those functions in just one function. This eliminates the need to apply both of those functions separately to a single array, piping the results of one function execution to the other.

The reduce() function serves the same purpose as the map() function because it allows you to return a different value depending on the value of each item in the array. The reduce() function serves the same purpose as the filter() function because it allows you to choose which items in the array will result in a value being reflected in the final function return value.

This reduce() function code sample may look more complicated than the for loop code sample on the surface, but one reason why I wanted to cover this function is because I think it is actually superior to an equivalent for loop implementation. This superiority stems from the fact that the reduce() function does not need to depend on the use of any variables external to the function in order to maintain its state across loop iterations.

The initial value parameter allows you to specify a starting point from which to work and you can build upon that initial value however you see fit throughout the duration of function execution. This keeps usage of the function more self-contained, which I think ultimately increases its readability over and above that of the for loop implementation.

Array.every() function

The every() function is the first function discussed in this article that does not have a guarantee to iterate through every item in the original array before function execution has completed. It is also unlike most of the previous functions in that it does not return an array of items in some way related to the items in the original array. Instead, it returns a simple boolean.

The every() function receives a parameter function as its sole parameter, and the only parameter for that function is each successive item in the original array. The function will iterate through each item in the array until it encounters an item for which the parameter function returns a falsy value. If this happens, the function ends execution early and returns false immediately. Otherwise, it iterates through every item in the original array and returns true . Let’s see a code sample using the every() function, along with the equivalent for loop code for comparison:

Javascript Array.every() function

In this code sample we are using the same input as before, but this time we are checking to see if every expense in our list of expenses has a total below a budget threshold. From the list of expenses on which the every() function is being executed, it is easy to see that the function will end execution and return false immediately after only the first iteration. When compared to the equivalent for loop code sample, which would also end execution of the loop after only the first iteration, I believe it is very clear to see the benefit of using the every() function over a for loop.

In the case of the equivalent for loop code, an external variable is required to track the ultimate result across loop iterations, which I believe instantly makes it far less readable than the every() function implementation, which keeps everything internal until the final function result is produced. The every() function code in this code sample could be read like this: Check if every expense in a list of expenses has an expense total under 100.

The real benefit of the every() function is what you are saying when you use this function in your code. Using this function on an array means that you are verifying that every item in that array passes whatever logical check you implement inside the parameter function.

Additionally, you are stating that you want to be notified immediately if just one of those items does not pass that logical check. This logical check acts as a short circuit and can provide an answer to your query much faster than it would take to check every single item in the array. The only time that you would need to iterate through the entire array is when it turns out that all items in the array have passed the logical check, which is perfectly acceptable and logically necessary.

Array.some() function

While the primary use of the every() function was to check an array for a single logical failure case, the primary function of the some() function is to check an array for a single logical success case. These two functions are essentially polar opposites in their purpose and how they approach evaluating an array. Like most of the other previous functions, the some() function takes a single parameter, a parameter function, and the only parameter of that function is each successive item in the original array.

The function will iterate through each item in the array until it encounters an item for which the parameter function returns a truthy value. If this happens, the function ends execution early and returns true immediately. Otherwise, it iterates through every item in the original array and returns false . Let’s see a code sample using the some() function, along with the equivalent for loop code for comparison:

Javascript Array.some() function

In this code sample we are using the same input as always while checking to see if at least one expense in a list of expenses has a total over a budget threshold. From the list of expenses that we have by now grown accustomed to using, it is easy to see that the function will end execution and return true immediately after only the first iteration. The some() function code in this code sample could be read like this: Check if some expense in a list of expenses has an expense total over 100.

Just like with the every() function code sample, usage of the some() function in this code sample offers a clear benefit over usage of the for loop. In fact, if you compare the for loop equivalent code from both code samples, you will see that they are almost identical, except for the fact that the initial value of the external variable is swapped with the short-circuit logic value defined inside the for loop. This is a real problem because if you were to see the for loop equivalent code from the two code samples next to each other, it is not immediately obvious that they are actually completely opposite in their intended logical purposes.

Usage of the some() and every() functions next to each other would not present the same problem, somewhat because the logic contained in the parameter functions is clearly opposite, but mostly because the names of the actual functions are clearly very different and indicate opposite behaviors.

Just like with the every() function, the real benefit of the some() function is what you are saying when you use this function in your code. Using this function on an array means that you are verifying that some item in that array passes whatever logical check you implement inside the parameter function.

Additionally, you are stating that you want to be notified immediately as soon as one of those items passes that logical check. This logical check acts as a short circuit and can provide an answer to your query much faster than it would take to check every single item in the array. The only time that you would need to iterate through the entire array is when none of the items in the array have passed the logical check, which makes sense from a logical standpoint.

Array.find() function

The last function that I want to discuss, the find() function, is quite similar to the some() function, but it does not return a simple boolean like that function does. The find() function takes a single parameter, a parameter function, and the only parameter of that function is each successive item in the original array.

Like the some() function, the find() function will iterate through each item in the original array until it encounters an item for which the parameter function returns a truthy value. If this happens, however, the function ends execution early and immediately returns the array item for which the truthy value was returned, rather than a simple boolean. Otherwise, the function iterates through every item in the original array and returns undefined . Let’s see a code sample using the find() function, along with the equivalent for loop code for comparison:

Javascript Array.find() function

This code sample is almost identical to the some() function code sample, both in the use of the find() function as well as in the for loop equivalent code. In fact, the only real difference is in what is returned as the ultimate value at the end of the function execution. From the list of expenses that we have been using throughout this article, it is clear that the function will end execution and return the first item in the list after only the first iteration. The find() function code in this code sample could be read like this: Find an expense in a list of expenses with an expense total over 100.

Just like in the case of the some() function code sample, the find() function code here is clearly superior because of its brevity, its ability to internally maintain all necessary results until function execution has finished, and the fact that the function name clearly indicates what type of operation is being executed on the original array. Just like with the every() and some() functions, if you were to see the for loop equivalent code for the find() function next to that for one of those functions, it would require much more attention and thought to distinguish the two for loops apart in terms of their ultimate purpose.

Since the find() function and some() function work identically except for their function return value, your choice between using them is defined by what you would like to do with the function return value. If you simply need to know that an array contains at least one item that passes a logical check and you do not need to know any more details about that item, then use the some() function. If you need to know more details about that item, then use the find() function.

Conclusions

In this article we covered a couple of the most common ways in which I have observed developers interacting with arrays in Javascript ( forEach() and map() ). Additionally, I presented several alternatives to those commonly used functions in order to not only highlight their existence but also to explain in what types of situations they can be used to better communicate the intentions of the code and ultimately its overall readability. I hope that this article will help many developers broaden their horizons when it comes to all Javascript array-related coding situations.

Resources

Javascript for loops

Javascript break statement

For loop code sample

Javascript Array.forEach() function

forEach() function code sample

Javascript Array.map() function

map() function code sample

Javascript Array.filter() function

filter() function code sample

Javascript Array.reduce() function

reduce() function code sample

Javascript Array.every() function

Javascript Falsy

every() function code sample

Javascript Array.some() function

Javascript Truthy

some() function code sample

Javascript Array.find() function

find() function code sample