Skip to main content

Command Palette

Search for a command to run...

Rethinking JS Array Methods (Part 2)

Updated
7 min read
Rethinking JS Array Methods (Part 2)

Preamble: There are currently 43 JavaScript Array methods listed at the MDN website. This discussion mentions 27 methods I've seen and used often in code.

In Rethinking JavaScript Array Methods (Part 1), I stated that each Array method could basically be categorized as belonging to one of two distinct groups:

  1. Methods that mutate the array.

  2. Methods that are non-mutating:
    a) those that return a new array,
    b) those that return a value,
    c) those that always return nothing.


Functional Purpose

In this article, let's begin by reorganizing and expanding our previous list to include the basic functional purpose... such as adding, updating, removing, re-ordering, and evaluating. The revised list will be:

  1. Mutating methods that change array items in place while:

    (a) adding values

    (b) updating items

    (c) removing items (returning the removed values)
    (d) re-ordering items

  2. Non-mutating methods that "copy" items to a new array while:
    (a) adding values

    (b) updating items

    (c) removing items (returning the removed values)
    (d) re-ordering items

  3. Methods that evalute the array, returning a single value, while:
    (a) checking a condition
    (b) finding an index
    (c) finding a value
    (d) combining all items

  4. Methods that access items for user-defined processing, then return undefined

Note: I put "copy" in quotes (see above) because only primitive values (eg. numbers, strings) are copied. Objects located inside the original-array are "shallow copied" to the new array by copying the associated reference id. In other words, both the original and new array will share the reference pointer to each "copied" object. So updating an object in one array will also update the other array. For more information on Shallow Copy, visit MDN Web Docs.


Mutating Methods = Changed Array

First, let's list methods that mutate/change the array while Adding, Updating, Removing or Re-ordering items.

Adding values:
push() adds values to the end of the array, eg. arr.push(value1, value2)
unshift() adds values to the start of the array, eg. arr.unshift(value1, value2)
BTW, the return value for both push() and unshift() is the new length of the array.
splice() can add values at a given index, eg. arr.splice(index, 0, value1, value2)
When just adding items with splice(), the second parameter is set to zero and the return will be an empty array since no items were removed.

Updating items:
splice() can update items at a given index, eg. arr.splice(index, 2, value1, value2)
When updating items, the second parameter equals the number of items to update.

Removing+Get items:
pop() removes the last item and returns that value, eg. arr.pop()
shift() removes the first item and returns that value, eg. arr.shift()
splice() at the given index, removes "count" items, eg. arr.splice(index, count)
Note: while pop() and shift() return just the removed item, the splice() method will return an array with any removed items.

Re-Ordering items:
reverse() reverses the order of items "in place" (ie. same array), eg. arr.reverse()
sort() sorts the items based on an a>b compare function, ie. arr.sort(compareFcn)
Note: a default compare results in an ascending sort based on the UTF-16 code for the string value of each item. Hence the number 100 will sort before 20... and 20 will sort before the number 3. So a good coding practice is to define all sort functions.

Notice the splice() method is especially useful since it can change the array by Adding, Updating and Removing. As an example, arr.splice(1, 2, value1, value2, value3) starts at index 1, removes 2 items, adds/updates 2 items, and adds a third value.


Non-Mutating Methods = New Array

Second, let's list non-mutating methods that shallow copies items into a new array while Adding, Updating, Removing or Re-ordering. In the process, the original array is left unchanged and the new array is returned.

Adding values:
concat() can add values to either the start or end of a new shallow-copied array, eg. arr.concat(value1, value2) adds values to the end, while [value1, value2].concat(arr) adds values to the start. Note, this method can also used be to combine (without removing duplicates) items from two arrays into a new array, eg. arr1.concat(arr2).
toSpliced() can add values at a given index, eg. arr.toSpliced(index, 0, val1, val2)

While not a method, the Spread Operator (...) can be used to "expand" (by shallow copying) all array items into a new array, along with additional values. An example with adding two values at the end is [...arr, value1, value2], and adding at the start is [value1, value2, ...arr].

Updating items:
with() updates the new array at index with a given value, eg. arr.with(index, value)
map() can update all items using a "edit" function , eg. arr.map(item => editFcn(item))
toSpliced() can update at index with values, eg. arr.toSpliced(index, 2, val1, val2)

Removing items:
filter() removes all items that fail a test function, eg. arr.filter(item => testFcn(item))
slice() removes items before start and from end indexes, eg. arr.slice(start, end)
toSpliced() removes number-of-items at given index, eg. arr.toSpliced(index, nmbrOf)

Basically, we can use filter() to remove a defined "type" of item,... or we can use toSpliced() to remove an indexed group of items,... or we can use slice() to remove all items except an indexed group.

Re-Ordering items:
toReversed() in reverse order, copies items into a new array, eg. arr.toReversed()
toSorted() compare-sorts copied items into a new array, eg. arr.toSorted(compareFcn)
Note: same as sort(), the default for toSorted() is based on the UTC-16 ascending string value.

Notice that toSpliced() can be used for Adding, Updating and Removing. For example, arr.toSpliced(1, 2, value1, value2, value3) will basically shallow copy the arr array... then starting at index 1, will remove 2 items, add/update two values and add a third value... returning a new edited copy of the original array.


Evaluating Methods = Single Value

Next, let's list methods that functionally evaluate items in the array.

Conditional check... returns true or false
some() true when item passes the test function, eg. arr.some(item => testFcn(item))
every() false when an item fails the test function, eg. arr.every(item => testFcn(item))
includes() true if the given item is in the array (at least once), eg. arr.includes(item)
Array.isArray() true if parameter is an array with some items, eg. Array.isArray(arr)

Find an index... returns the index or -1
indexOf() returns index of the first instance of a given item, eg. arr.indexOf(item)
lastIndexOf() index of the last instance of a given item, eg. arr.lastIndexOf(item)
findIndex() index of first item to pass test, eg. arr.findIndex(item => testFcn(item))

Find a value... returns the value or undefined
at() will return the value (if any) at a given index reference number, eg. arr.at(index)
Note: negative index references can be used, where -1 refers to the last array item.
find() return the first value to pass a test function, eg. arr.find(item => testFcn(item))

Combine all items... returns a single value.
join() will recursively convert items to type string and join them with a separator, eg. arr.join(separator). Note that the default separator is a comma with no spacing, so for example [1, "a", [2, "b"]].join() would return the string "1,a,2,b".
reduce() calculates the accumulated value for all the array items. For example, to find the sum of an array of numbers, we can use arr.reduce((acc, curValue) => acc + curValue, initValue)... where the accumulator acc is initialized to initValue 0 for addition (1 for multiplication) and the current value curValue is iteratively set to the value of each array item, beginning at index 0. See MDN Web Docs for a complete explanation.

Also note the Array length property, eg. arr.length, is a quick and simple way to obtain the current number of items in an array.


General Purpose Methods

In the final category, I will note a method that iterates through an array to access each item for user-defined processing... afterwhich the method returns undefined

forEach() user-defined process each item, eg. arr.forEach(item => processFcn(item))
Note: for asynchronous functions that loop through an array, use the for...of loop.


Closing Comments

My goal for this article was to "rethink" how I understood many of the commonly used Array methods and thereby organize them into "easier to remember" categories based on their basic functional purpose and whether the method directly mutates the array.

I hope this article is helpful to others learning Array methods. As always, my inner-drive to properly learn coding concepts continues to be an ongoing process. ;-)

Final Note

Much of the content for this article was originally gathered while I prepared for the second part of a Scrimba Bootcamp Workshop on JavaScript Array Methods, presented in late December, 2023. -- Paul O.

References

  1. MDN Web Docs @ https://developer.mozilla.org/

  2. W3 Schools @ https://www.w3schools.com/